home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume23 / trn / part07 < prev    next >
Encoding:
Text File  |  1991-08-22  |  63.9 KB  |  2,717 lines

  1. This is a new archive version of TRN at patchlevel 3.
  2. The original posting took up Volume23, issues 60 to 73, with
  3. various problems.  These files replace those issues.
  4.  
  5. #! /bin/sh
  6. # This is a shell archive.  Remove anything before this line, then feed it
  7. # into a shell via "sh file" or similar.  To overwrite existing files,
  8. # type "sh file -c".
  9. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  10. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  11. # Contents:  mt-write.c rcstuff.c term.c
  12. # Wrapped by rsalz@litchi.bbn.com on Fri Aug 23 16:38:56 1991
  13. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  14. echo If this archive is complete, you will see the following message:
  15. echo '          "shar: End of archive 7 (of 14)."'
  16. if test -f 'mt-write.c' -a "${1}" != "-c" ; then 
  17.   echo shar: Will not clobber existing file \"'mt-write.c'\"
  18. else
  19.   echo shar: Extracting \"'mt-write.c'\" \(9495 characters\)
  20.   sed "s/^X//" >'mt-write.c' <<'END_OF_FILE'
  21. X/* $Header: mt-write.c,v 4.3.3.2 91/01/16 02:49:17 davison Trn $
  22. X**
  23. X** $Log:    mt-write.c,v $
  24. X** Revision 4.3.3.2  91/01/16  02:49:17  davison
  25. X** Tweaked fopen for possible binary open mode.
  26. X** 
  27. X** Revision 4.3.3.1  90/07/24  23:51:18  davison
  28. X** Initial Trn Release
  29. X** 
  30. X*/
  31. X
  32. X#include "EXTERN.h"
  33. X#include "common.h"
  34. X#include "mthreads.h"
  35. X
  36. Xstatic FILE *fp_out;
  37. Xstatic int seq;
  38. Xstatic int article_seq;
  39. X
  40. Xstatic int failure;
  41. X
  42. Xvoid write_subjects(), write_authors(), write_roots(), write_ids();
  43. Xvoid write_articles(), write_thread(), write_item();
  44. Xvoid enumerate_articles(), enumerate_thread();
  45. Xvoid free_leftovers();
  46. X
  47. X/* Write out all the data in a packed format that is easy for our newsreader
  48. X** to use.  We free things as we go, when we don't need them any longer.  If
  49. X** we encounter any write errors, the write_item routine sets a failure flag
  50. X** to halt our writing of the file, but we keep on plugging away to free
  51. X** everything up.
  52. X*/
  53. Xint
  54. Xwrite_data( filename )
  55. Xchar *filename;
  56. X{
  57. X    if( filename == Nullch ) {
  58. X    failure = 2;    /* A NULL filename indicates just free the data */
  59. X    } else if( !ensure_path( filename ) ) {
  60. X    log_error( "Unable to create path: `%s'.\n", filename );
  61. X    failure = 2;
  62. X    } else if( (fp_out = fopen( filename, FOPEN_WB )) == Nullfp ) {
  63. X    log_error( "Unable to create file: `%s'.\n", filename );
  64. X    failure = 2;
  65. X    } else {
  66. X    failure = 0;
  67. X    }
  68. X    write_item( &total, sizeof (TOTAL) );
  69. X
  70. X    enumerate_articles();
  71. X
  72. X    write_authors();
  73. X    write_subjects();
  74. X    write_roots();
  75. X    write_articles();
  76. X    write_ids();
  77. X    free_leftovers();
  78. X
  79. X    if( failure != 2 ) {
  80. X    fclose( fp_out );
  81. X    }
  82. X    if( failure == 1 ) {
  83. X    log_error( "Write failed!  Removing `%s'.\n", filename );
  84. X    unlink( filename );
  85. X    }
  86. X    return !failure;
  87. X}
  88. X
  89. X/* Recursively descend the article tree, enumerating the articles as we go.
  90. X** This way we can output the article sequence numbers into the data file.
  91. X*/
  92. Xvoid
  93. Xenumerate_articles()
  94. X{
  95. X    register ROOT *root;
  96. X
  97. X    seq = article_seq = 0;
  98. X
  99. X    for( root = root_root; root; root = root->link ) {
  100. X    root->seq = seq++;
  101. X    if( !root->articles ) {
  102. X        log_error( "** No articles on this root??\n" );
  103. X        continue;
  104. X    }
  105. X    enumerate_thread( root->articles );
  106. X    }
  107. X    if( seq != total.root ) {
  108. X    log_error( "** Wrote %d roots instead of %d **\n", seq, total.root );
  109. X    }
  110. X    if( article_seq != total.article ) {
  111. X    log_error( "** Wrote %d articles instead of %d **\n", article_seq, total.article );
  112. X    }
  113. X}
  114. X
  115. X/* Recursive routine for above-mentioned enumeration. */
  116. Xvoid
  117. Xenumerate_thread( article )
  118. XARTICLE *article;
  119. X{
  120. X    while( article ) {
  121. X    article->seq = article_seq++;
  122. X    if( article->children ) {
  123. X        enumerate_thread( article->children );
  124. X    }
  125. X    article = article->siblings;
  126. X    }
  127. X}
  128. X
  129. X#define write_and_free( str_ptr )    /* Comment for makedepend to     \
  130. X                    ** ignore the backslash above */ \
  131. X{\
  132. X    register int len = strlen( str_ptr ) + 1;\
  133. X    write_item( str_ptr, len );\
  134. X    free( str_ptr );\
  135. X    string_offset += len;\
  136. X}
  137. X
  138. XMEM_SIZE string_offset;
  139. X
  140. X/* Write out the author information:  first the use-counts, then the
  141. X** name strings all packed together.
  142. X*/
  143. Xvoid
  144. Xwrite_authors()
  145. X{
  146. X    register AUTHOR *author;
  147. X
  148. X    seq = 0;
  149. X    for( author = author_root; author; author = author->link ) {
  150. X    write_item( &author->count, sizeof (WORD) );
  151. X    author->seq = seq++;
  152. X    }
  153. X    if( seq != total.author ) {
  154. X    log_error( "** Wrote %d authors instead of %d **\n",
  155. X        seq, total.author );
  156. X    }
  157. X
  158. X    string_offset = 0;
  159. X
  160. X    for( author = author_root; author; author = author->link ) {
  161. X    write_and_free( author->name );
  162. X    }
  163. X}
  164. X
  165. X/* Write out the subject information: first the packed string data, then
  166. X** the use-counts.  The order is important -- it is the order required
  167. X** by the roots for their subject structures.
  168. X*/
  169. Xvoid
  170. Xwrite_subjects()
  171. X{
  172. X    register ROOT *root;
  173. X    register SUBJECT *subject;
  174. X
  175. X    for( root = root_root; root; root = root->link ) {
  176. X    for( subject = root->subjects; subject; subject = subject->link ) {
  177. X        write_and_free( subject->str );
  178. X    }
  179. X    }
  180. X    if( string_offset != total.string1 ) {
  181. X    log_error( "** Author/subject strings were %ld bytes instead of %ld **\n",
  182. X        string_offset, total.string1 );
  183. X    }
  184. X
  185. X    seq = 0;
  186. X    for( root = root_root; root; root = root->link ) {
  187. X    for( subject = root->subjects; subject; subject = subject->link ) {
  188. X        write_item( &subject->count, sizeof (WORD) );
  189. X        subject->seq = seq++;
  190. X    }
  191. X    }
  192. X    if( seq != total.subject ) {
  193. X    log_error( "** Wrote %d subjects instead of %d **\n",
  194. X        seq, total.subject );
  195. X    }
  196. X}
  197. X
  198. X/* Write the roots in a packed format.  Interpret the pointers into
  199. X** sequence numbers as we go.
  200. X*/
  201. Xvoid
  202. Xwrite_roots()
  203. X{
  204. X    register ROOT *root;
  205. X
  206. X    for( root = root_root; root; root = root->link ) {
  207. X    p_root.articles = root->articles->seq;
  208. X    p_root.root_num = root->root_num;
  209. X    p_root.thread_cnt = root->thread_cnt;
  210. X    p_root.subject_cnt = root->subject_cnt;
  211. X    write_item( &p_root, sizeof (PACKED_ROOT) );
  212. X    }
  213. X}
  214. X
  215. X#define rel_article( article, rseq )    ((article)? (article)->seq - (rseq) : 0)
  216. X#define valid_seq( ptr )        ((ptr)? (ptr)->seq : -1)
  217. X
  218. X/* Write all the articles in the same order that we sequenced them. */
  219. Xvoid
  220. Xwrite_articles()
  221. X{
  222. X    register ROOT *root;
  223. X
  224. X    for( root = root_root; root; root = root->link ) {
  225. X    write_thread( root->articles );
  226. X    }
  227. X}
  228. X
  229. X/* Recursive routine to write the article in thread order.  We depend on
  230. X** the fact that our first child is the very next article written (if we
  231. X** have children).
  232. X*/
  233. Xvoid
  234. Xwrite_thread( article )
  235. Xregister ARTICLE *article;
  236. X{
  237. X    while( article ) {
  238. X    p_article.num = article->num;
  239. X    p_article.date = article->date;
  240. X    p_article.subject = valid_seq( article->subject );
  241. X    p_article.author = valid_seq( article->author );
  242. X    p_article.flags = (article->flags & ~NEW_ARTICLE);
  243. X    p_article.child_cnt = article->child_cnt;
  244. X    p_article.parent = rel_article( article->parent, article->seq );
  245. X    p_article.siblings = rel_article( article->siblings, article->seq );
  246. X    p_article.root = article->root->seq;
  247. X    write_item( &p_article, sizeof (PACKED_ARTICLE) );
  248. X    if( article->children ) {
  249. X        write_thread( article->children );
  250. X    }
  251. X    article = article->siblings;
  252. X    }
  253. X}
  254. X
  255. XWORD minus_one = -1;
  256. X
  257. X/* Write the message-id strings:  each domain name (not including the
  258. X** ".unknown." domain) followed by all of its associated unique ids.
  259. X** Then output the article sequence numbers they belong to.  This stuff
  260. X** is last because the newsreader doesn't need to read it.
  261. X*/
  262. Xvoid
  263. Xwrite_ids()
  264. X{
  265. X    register DOMAIN *domain;
  266. X    register ARTICLE *id;
  267. X    register DOMAIN *next_domain;
  268. X    register ARTICLE *next_id;
  269. X
  270. X    string_offset = 0;
  271. X
  272. X    for( domain = &unk_domain; domain; domain = domain->link ) {
  273. X    if( domain != &unk_domain ) {
  274. X        write_and_free( domain->name );
  275. X        if( !domain->ids ) {
  276. X        log_error( "** Empty domain name!! **\n" );
  277. X        }
  278. X    }
  279. X    for( id = domain->ids; id; id = id->id_link ) {
  280. X        write_and_free( id->id );
  281. X    }
  282. X    }
  283. X    if( string_offset != total.string2 ) {
  284. X    log_error( "** Message-id strings were %ld bytes (%ld) **\n",
  285. X        string_offset, total.string2 );
  286. X    }
  287. X    for( domain = &unk_domain; domain; domain = next_domain ) {
  288. X    next_domain = domain->link;
  289. X    for( id = domain->ids; id; id = next_id ) {
  290. X        next_id = id->id_link;
  291. X        write_item( &id->seq, sizeof (WORD) );
  292. X        free( id );
  293. X    }
  294. X    write_item( &minus_one, sizeof (WORD) );
  295. X    if( domain != &unk_domain ) {
  296. X        free( domain );
  297. X    }
  298. X    }
  299. X    unk_domain.ids = Nullart;
  300. X    unk_domain.link = Null(DOMAIN*);
  301. X}
  302. X
  303. X/* Free everything that's left to free.
  304. X*/
  305. Xvoid
  306. Xfree_leftovers()
  307. X{
  308. X    register ROOT *root, *next_root;
  309. X    register SUBJECT *subj, *next_subj;
  310. X    register AUTHOR *author, *next_author;
  311. X
  312. X    for( root = root_root; root; root = next_root ) {
  313. X    next_root = root->link;
  314. X    for( subj = root->subjects; subj; subj = next_subj ) {
  315. X        next_subj = subj->link;
  316. X        free( subj );
  317. X    }
  318. X    free( root );
  319. X    }
  320. X    for( author = author_root; author; author = next_author ) {
  321. X    next_author = author->link;
  322. X    free( author );
  323. X    }
  324. X    root_root = Null(ROOT*);
  325. X    author_root = Null(AUTHOR*);
  326. X}
  327. X
  328. X/* This routine will check to be sure that the required path exists for
  329. X** the data file, and if not it will attempt to create it.
  330. X*/
  331. Xint
  332. Xensure_path( filename )
  333. Xregister char *filename;
  334. X{
  335. X    int status, pid, w;
  336. X    char tmpbuf[1024];
  337. X#ifdef MAKEDIR
  338. X    register char *cp, *last;
  339. X    register char *tbptr = tmpbuf+5;
  340. X
  341. X    if( !(last = rindex( filename, '/' )) ) {    /* find filename portion */
  342. X    return 1;                /* no path, we're fine */
  343. X    }
  344. X    *last = '\0';                /* truncate path at filename */
  345. X    strcpy( tmpbuf, "mkdir" );
  346. X
  347. X    for( cp = last;; ) {
  348. X    if( stat( filename, &filestat ) >= 0 && (filestat.st_mode & S_IFDIR) ) {
  349. X        *cp = '/';
  350. X        break;
  351. X    }
  352. X    if( !(cp = rindex( filename, '/' )) ) {/* find something that exists */
  353. X        break;
  354. X    }
  355. X    *cp = '\0';
  356. X    }
  357. X    
  358. X    for( cp = filename; cp <= last; cp++ ) {
  359. X    if( !*cp ) {
  360. X        sprintf( tbptr, " %s", filename );
  361. X        tbptr += strlen( tbptr );        /* set up for mkdir call */
  362. X        *cp = '/';
  363. X    }
  364. X    }
  365. X    if( tbptr == tmpbuf+5 ) {
  366. X    return 1;
  367. X    }
  368. X#else
  369. X    sprintf(tmpbuf,"%s %s %d", filexp(DIRMAKER), filename, 1);
  370. X#endif
  371. X
  372. X    if ((pid = vfork()) == 0) {
  373. X    execl(SH, SH, "-c", tmpbuf, Nullch);
  374. X    _exit(127);
  375. X    }
  376. X    while ((w = wait(&status)) != pid && w != -1)
  377. X    ;
  378. X    if (w == -1)
  379. X    status = -1;
  380. X    return !status;
  381. X}
  382. X
  383. X/* A simple routine to output some data only if we haven't failed any
  384. X** previous writes.
  385. X*/
  386. Xvoid
  387. Xwrite_item( buff, len )
  388. Xchar *buff;
  389. Xint len;
  390. X{
  391. X    if( !failure ) {
  392. X    if( fwrite( buff, 1, len, fp_out ) < len ) {
  393. X        failure = 1;
  394. X    }
  395. X    }
  396. X}
  397. END_OF_FILE
  398.   if test 9495 -ne `wc -c <'mt-write.c'`; then
  399.     echo shar: \"'mt-write.c'\" unpacked with wrong size!
  400.   fi
  401.   # end of 'mt-write.c'
  402. fi
  403. if test -f 'rcstuff.c' -a "${1}" != "-c" ; then 
  404.   echo shar: Will not clobber existing file \"'rcstuff.c'\"
  405. else
  406.   echo shar: Extracting \"'rcstuff.c'\" \(25009 characters\)
  407.   sed "s/^X//" >'rcstuff.c' <<'END_OF_FILE'
  408. X/* $Header: rcstuff.c,v 4.3.3.3 91/01/16 03:28:34 davison Trn $
  409. X *
  410. X * $Log:    rcstuff.c,v $
  411. X * Revision 4.3.3.3  91/01/16  03:28:34  davison
  412. X * Integrated rn patches 48-54.  Fixed in_char and verify interaction.
  413. X * 
  414. X * Revision 4.3.3.2  90/08/20  16:47:44  davison
  415. X * Removed ngmax array.
  416. X * 
  417. X * Revision 4.3.3.1  90/06/20  22:39:28  davison
  418. X * Initial Trn Release
  419. X * 
  420. X * Revision 4.3.2.12  90/12/12  03:05:15  sob
  421. X * Adds "N" command to compliment the "Y" command when prompted for adding
  422. X * new newsgroups.
  423. X * 
  424. X * Revision 4.3.2.11  90/11/22  17:49:57  sob
  425. X * Fixed "Y" for regular rn users (non-NNTP).
  426. X * 
  427. X * Revision 4.3.2.10  90/11/22  13:53:26  sob
  428. X * Made changes to keep more preprocessors happy.
  429. X * 
  430. X * Revision 4.3.2.9  90/11/06  01:04:39  sob
  431. X * Updated help messages to include new Y command when adding new newsgroups.
  432. X * 
  433. X * Revision 4.3.2.8  90/10/30  23:26:43  sob
  434. X * Changes to restore .newsrc when exiting rn and diskspace runs out while
  435. X * updating .newsrc.
  436. X * 
  437. X * Revision 4.3.2.7  90/10/30  22:47:49  sob
  438. X * A bit of cleanup.
  439. X * 
  440. X * Revision 4.3.2.6  90/09/04  23:36:32  sob
  441. X * Changed "add" to "subscribe" to actually reflect what is being done.
  442. X * 
  443. X * Revision 4.3.2.5  90/05/04  00:44:07  sob
  444. X * Fixes to add_newsgroup() from lar@usl.edu.
  445. X * 
  446. X * Revision 4.3.2.4  90/04/23  00:25:45  sob
  447. X * Changed atoi to atol.
  448. X * 
  449. X * Revision 4.3.2.3  89/12/20  23:25:04  sob
  450. X * Changed the maximum lenght of a newsgroup name from 20 to 40 characters.
  451. X * 
  452. X * Revision 4.3.2.2  89/11/26  18:22:26  sob
  453. X * Added changes to addnewgroup() to cause rn to ask once and only once
  454. X * to add a new group to .newsrc. 
  455. X * Fix provided by Fletcher Mattox <fletcher@cs.utexas.edu>
  456. X * 
  457. X * Revision 4.3.2.1  89/11/06  00:58:29  sob
  458. X * Added RRN support from NNTP 1.5
  459. X * 
  460. X * Revision 4.3.1.5  86/07/24  14:09:10  lwall
  461. X * Removed check for spool directory existence in get_ng.
  462. X * 
  463. X * Revision 4.3.1.4  85/09/10  11:04:44  lwall
  464. X * Improved %m in in_char().
  465. X * 
  466. X * Revision 4.3.1.3  85/05/29  09:13:25  lwall
  467. X * %d that should be %ld.
  468. X * 
  469. X * Revision 4.3.1.2  85/05/17  11:40:08  lwall
  470. X * Sped up "rn -c" by not mallocing unnecessarily.
  471. X * 
  472. X * Revision 4.3.1.1  85/05/10  11:37:18  lwall
  473. X * Branch for patches.
  474. X * 
  475. X * Revision 4.3  85/05/01  11:45:56  lwall
  476. X * Baseline for release with 4.3bsd.
  477. X * 
  478. X */
  479. X
  480. X#include "EXTERN.h"
  481. X#include "common.h"
  482. X#include "util.h"
  483. X#include "ngdata.h"
  484. X#include "term.h"
  485. X#include "final.h"
  486. X#include "rn.h"
  487. X#include "intrp.h"
  488. X#include "only.h"
  489. X#include "rcln.h"
  490. X#ifdef SERVER
  491. X#include "server.h"
  492. X#endif
  493. X#include "INTERN.h"
  494. X#include "rcstuff.h"
  495. X
  496. Xchar *rcname INIT(Nullch);        /* path name of .newsrc file */
  497. Xchar *rctname INIT(Nullch);        /* path name of temp .newsrc file */
  498. Xchar *rcbname INIT(Nullch);        /* path name of backup .newsrc file */
  499. Xchar *softname INIT(Nullch);        /* path name of .rnsoft file */
  500. XFILE *rcfp INIT(Nullfp);            /* .newsrc file pointer */
  501. X
  502. X#ifdef HASHNG
  503. X    short hashtbl[HASHSIZ];
  504. X#endif
  505. X
  506. Xbool
  507. Xrcstuff_init()
  508. X{
  509. X    register NG_NUM newng;
  510. X    register char *s;
  511. X    register int i;
  512. X    register bool foundany = FALSE;
  513. X    char *some_buf;
  514. X    long length;
  515. X#ifdef SERVER
  516. X    char *cp;
  517. X#endif /* SERVER */
  518. X
  519. X#ifdef HASHNG
  520. X    for (i=0; i<HASHSIZ; i++)
  521. X    hashtbl[i] = -1;
  522. X#endif
  523. X
  524. X    /* make filenames */
  525. X
  526. X#ifdef SERVER
  527. X
  528. X    if (cp = getenv("NEWSRC"))
  529. X    rcname = savestr(filexp(cp));
  530. X    else
  531. X    rcname = savestr(filexp(RCNAME));
  532. X
  533. X#else /* not SERVER */
  534. X
  535. X    rcname = savestr(filexp(RCNAME));
  536. X
  537. X#endif /* SERVER */
  538. X
  539. X    rctname = savestr(filexp(RCTNAME));
  540. X    rcbname = savestr(filexp(RCBNAME));
  541. X    softname = savestr(filexp(SOFTNAME));
  542. X    
  543. X    /* make sure the .newsrc file exists */
  544. X
  545. X    newsrc_check();
  546. X
  547. X    /* open .rnsoft file containing soft ptrs to active file */
  548. X
  549. X    tmpfp = fopen(softname,"r");
  550. X    if (tmpfp == Nullfp)
  551. X    writesoft = TRUE;
  552. X
  553. X    /* read in the .newsrc file */
  554. X
  555. X    for (nextrcline = 0;
  556. X    (some_buf = get_a_line(buf,LBUFLEN,rcfp)) != Nullch;
  557. X    nextrcline++) {
  558. X                    /* for each line in .newsrc */
  559. X    char tmpbuf[10];
  560. X
  561. X    newng = nextrcline;        /* get it into a register */
  562. X    length = len_last_line_got;    /* side effect of get_a_line */
  563. X    if (length <= 1) {        /* only a newline??? */
  564. X        nextrcline--;        /* compensate for loop increment */
  565. X        continue;
  566. X    }
  567. X    if (newng >= MAXRCLINE) {    /* check for overflow */
  568. X        fputs("Too many lines in .newsrc\n",stdout) FLUSH;
  569. X        finalize(1);
  570. X    }
  571. X    if (tmpfp != Nullfp && fgets(tmpbuf,10,tmpfp) != Nullch)
  572. X        softptr[newng] = atol(tmpbuf);
  573. X    else
  574. X        softptr[newng] = 0;
  575. X    some_buf[--length] = '\0';    /* wipe out newline */
  576. X    if (checkflag)            /* no extra mallocs for -c */
  577. X        rcline[newng] = some_buf;
  578. X    else if (some_buf == buf) {
  579. X        rcline[newng] = savestr(some_buf);
  580. X                    /* make a semipermanent copy */
  581. X    }
  582. X    else {
  583. X        /*NOSTRICT*/
  584. X#ifndef lint
  585. X        some_buf = saferealloc(some_buf,(MEM_SIZE)(length+1));
  586. X#endif /* lint */
  587. X        rcline[newng] = some_buf;
  588. X    }
  589. X#ifdef NOTDEF
  590. X    if (strnEQ(some_buf,"to.",3)) {    /* is this a non-newsgroup? */
  591. X        nextrcline--;        /* destroy this line */
  592. X        continue;
  593. X    }
  594. X#endif
  595. X    if (*some_buf == ' ' ||
  596. X      *some_buf == '\t' ||
  597. X      strnEQ(some_buf,"options",7)) {        /* non-useful line? */
  598. X        toread[newng] = TR_JUNK;
  599. X        rcchar[newng] = ' ';
  600. X        rcnums[newng] = 0;
  601. X        continue;
  602. X    }
  603. X    for (s = rcline[newng]; *s && *s != ':' && *s != NEGCHAR; s++) ;
  604. X    if (!*s && !checkflag) {
  605. X#ifndef lint
  606. X        rcline[newng] = saferealloc(rcline[newng],(MEM_SIZE)length+2);
  607. X#endif /* lint */
  608. X        s = rcline[newng] + length;
  609. X        *s = ':';
  610. X        *(s+1) = '\0';
  611. X    }
  612. X    rcchar[newng] = *s;        /* salt away the : or ! */
  613. X    rcnums[newng] = (char)(s - rcline[newng]); 
  614. X    rcnums[newng]++;        /* remember where it was */
  615. X    *s = '\0';            /* null terminate newsgroup name */
  616. X#ifdef HASHNG
  617. X    if (!checkflag)
  618. X        sethash(newng);
  619. X#endif
  620. X    if (rcchar[newng] == NEGCHAR) {
  621. X        toread[newng] = TR_UNSUB;
  622. X        continue;
  623. X    }
  624. X
  625. X    /* now find out how much there is to read */
  626. X
  627. X    if (!inlist(buf) || (suppress_cn && foundany && !paranoid))
  628. X        toread[newng] = TR_NONE;    /* no need to calculate now */
  629. X    else
  630. X        set_toread(newng);
  631. X#ifdef VERBOSE
  632. X    if (!checkflag && softmisses == 1) {
  633. X        softmisses++;        /* lie a little */
  634. X        fputs("(Revising soft pointers--be patient.)\n",stdout) FLUSH;
  635. X    }
  636. X#endif
  637. X    if (toread[newng] > TR_NONE) {    /* anything unread? */
  638. X        if (!foundany) {
  639. X        starthere = newng;
  640. X        foundany = TRUE;    /* remember that fact*/
  641. X        }
  642. X        if (suppress_cn) {        /* if no listing desired */
  643. X        if (checkflag) {    /* if that is all they wanted */
  644. X            finalize(1);    /* then bomb out */
  645. X        }
  646. X        }
  647. X        else {
  648. X#ifdef VERBOSE
  649. X        IF(verbose)
  650. X            printf("Unread news in %-40s %5ld article%s\n",
  651. X            rcline[newng],(long)toread[newng],
  652. X            toread[newng]==TR_ONE ? nullstr : "s") FLUSH;
  653. X        ELSE
  654. X#endif
  655. X#ifdef TERSE
  656. X            printf("%s: %ld article%s\n",
  657. X            rcline[newng],(long)toread[newng],
  658. X            toread[newng]==TR_ONE ? nullstr : "s") FLUSH;
  659. X#endif
  660. X        if (int_count) {
  661. X            countdown = 1;
  662. X            int_count = 0;
  663. X        }
  664. X        if (countdown) {
  665. X            if (! --countdown) {
  666. X            fputs("etc.\n",stdout) FLUSH;
  667. X            if (checkflag)
  668. X                finalize(1);
  669. X            suppress_cn = TRUE;
  670. X            }
  671. X        }
  672. X        }
  673. X    }
  674. X    }
  675. X    fclose(rcfp);            /* close .newsrc */
  676. X    if (tmpfp != Nullfp)
  677. X    fclose(tmpfp);            /* close .rnsoft */
  678. X    if (checkflag) {            /* were we just checking? */
  679. X    finalize(foundany);        /* tell them what we found */
  680. X    }
  681. X    if (paranoid)
  682. X    cleanup_rc();
  683. X
  684. X#ifdef DEBUGGING
  685. X    if (debug & DEB_HASH) {
  686. X    page_init();
  687. X    for (i=0; i<HASHSIZ; i++) {
  688. X        sprintf(buf,"%d    %d",i,hashtbl[i]);
  689. X        print_lines(buf,NOMARKING);
  690. X    }
  691. X    }
  692. X#endif
  693. X
  694. X    return foundany;
  695. X}
  696. X
  697. X/* try to find or add an explicitly specified newsgroup */
  698. X/* returns TRUE if found or added, FALSE if not. */
  699. X/* assumes that we are chdir'ed to SPOOL */
  700. X
  701. X#define ADDNEW_SUB 1
  702. X#define ADDNEW_UNSUB 2
  703. X
  704. Xstatic int addnewbydefault = 0;
  705. X
  706. Xbool
  707. Xget_ng(what,do_reloc)
  708. Xchar *what;
  709. Xbool do_reloc;
  710. X{
  711. X    char *ntoforget;
  712. X    char promptbuf[128];
  713. X#ifdef SERVER
  714. X    char ser_line[256];
  715. X#endif /* SERVER */
  716. X
  717. X#ifdef VERBOSE
  718. X    IF(verbose)
  719. X    ntoforget = "Type n to forget about this newsgroup.\n";
  720. X    ELSE
  721. X#endif
  722. X#ifdef TERSE
  723. X    ntoforget = "n to forget it.\n";
  724. X#endif
  725. X    if (index(what,'/')) {
  726. X    dingaling();
  727. X    printf("\nBad newsgroup name.\n") FLUSH;
  728. X    return FALSE;
  729. X    }
  730. X    set_ngname(what);
  731. X    ng = find_ng(ngname);
  732. X    if (ng == nextrcline) {        /* not in .newsrc? */
  733. X
  734. X#ifdef SERVER
  735. X    sprintf(ser_line, "GROUP %s", ngname);
  736. X    put_server(ser_line);
  737. X    if (get_server(ser_line, sizeof(ser_line)) < 0) {
  738. X        fprintf(stderr, "rrn: Unexpected close of server socket.\n");
  739. X        finalize(1);
  740. X    }
  741. X    if (*ser_line != CHAR_OK) {
  742. X        if (atoi(ser_line) != ERR_NOGROUP) {
  743. X        fprintf(stderr, "Server response to GROUP %s:\n%s\n",
  744. X            ngname, ser_line);
  745. X        }
  746. X#else /* not SERVER */
  747. X
  748. X    if ((softptr[ng] = findact(buf,ngname,strlen(ngname),0L)) < 0 ) {
  749. X
  750. X#endif /* SERVER */
  751. X
  752. X        dingaling();
  753. X#ifdef VERBOSE
  754. X        IF(verbose)
  755. X        printf("\nNewsgroup %s does not exist!\n",ngname) FLUSH;
  756. X        ELSE
  757. X#endif
  758. X#ifdef TERSE
  759. X        printf("\nNo %s!\n",ngname) FLUSH;
  760. X#endif
  761. X        sleep(2);
  762. X        return FALSE;
  763. X    }
  764. X    if (addnewbydefault) {
  765. X        printf("(Adding %s to end of your .newsrc %ssubscribed)\n",
  766. X               ngname, (addnewbydefault == ADDNEW_SUB) ? "" : "un");
  767. X        if (addnewbydefault == ADDNEW_SUB)
  768. X             ng = add_newsgroup(ngname, ':');
  769. X        else
  770. X             ng = add_newsgroup(ngname, '!');
  771. X            do_reloc = FALSE;
  772. X    } else {
  773. X#ifdef VERBOSE
  774. X    IF(verbose)
  775. X        sprintf(promptbuf,"\nNewsgroup %s not in .newsrc--subscribe? [ynYN] ",ngname);
  776. X    ELSE
  777. X#endif
  778. X#ifdef TERSE
  779. X        sprintf(promptbuf,"\nSubscribe %s? [ynY] ",ngname);
  780. X#endif
  781. Xreask_add:
  782. X    in_char(promptbuf,'A');
  783. X    setdef(buf,"y");
  784. X#ifdef VERIFY
  785. X    printcmd();
  786. X#endif
  787. X    putchar('\n') FLUSH;
  788. X    if (*buf == 'h') {
  789. X#ifdef VERBOSE
  790. X        IF(verbose)
  791. X        printf("Type y or SP to add %s to your .newsrc.\nType Y to add all new groups to the end of your .newsrc.\nType N to add all new groups to the end of your .newsrc unsubscribed.\n", ngname)
  792. X          FLUSH;
  793. X        ELSE
  794. X#endif
  795. X#ifdef TERSE
  796. X        fputs("y or SP to add, Y to add all new groups, N to add all new groups unsubscribed\n",stdout) FLUSH;
  797. X#endif
  798. X        fputs(ntoforget,stdout) FLUSH;
  799. X        goto reask_add;
  800. X    }
  801. X    else if (*buf == 'n' || *buf == 'q') {
  802. X        ng = add_newsgroup(ngname, '!');
  803. X        return FALSE;
  804. X    }
  805. X    else if (*buf == 'y') {
  806. X        ng = add_newsgroup(ngname, ':');
  807. X        do_reloc = FALSE;
  808. X    }
  809. X    else if (*buf == 'Y') {
  810. X        fputs(
  811. X    "(I'll add all new newsgroups (subscribed) to the end of your .newsrc.)\n",
  812. X          stdout);
  813. X        addnewbydefault = ADDNEW_SUB;
  814. X        printf("(Adding %s to end of your .newsrc subscribed)\n", ngname);
  815. X        ng = add_newsgroup(ngname, ':');
  816. X        do_reloc = FALSE;
  817. X    }
  818. X    else if (*buf == 'N') {
  819. X        fputs(
  820. X  "(I'll add all new newsgroups (unsubscribed) to the end of your .newsrc.)\n",
  821. X          stdout);
  822. X        addnewbydefault = ADDNEW_UNSUB;
  823. X        printf("(Adding %s to end of your .newsrc unsubscribed)\n", ngname);
  824. X        ng = add_newsgroup(ngname, '!');
  825. X        do_reloc = FALSE;
  826. X    }
  827. X    else {
  828. X        fputs(hforhelp,stdout) FLUSH;
  829. X        settle_down();
  830. X        goto reask_add;
  831. X    }
  832. X      }
  833. X    }
  834. X    else if (rcchar[ng] == NEGCHAR) {    /* unsubscribed? */
  835. X#ifdef VERBOSE
  836. X    IF(verbose)
  837. X        sprintf(promptbuf,
  838. X"\nNewsgroup %s is currently unsubscribed to--resubscribe? [yn] ",ngname)
  839. X  FLUSH;
  840. X    ELSE
  841. X#endif
  842. X#ifdef TERSE
  843. X        sprintf(promptbuf,"\n%s unsubscribed--resubscribe? [yn] ",ngname)
  844. X          FLUSH;
  845. X#endif
  846. Xreask_unsub:
  847. X    in_char(promptbuf,'R');
  848. X    setdef(buf,"y");
  849. X#ifdef VERIFY
  850. X    printcmd();
  851. X#endif
  852. X    putchar('\n') FLUSH;
  853. X    if (*buf == 'h') {
  854. X#ifdef VERBOSE
  855. X        IF(verbose)
  856. X        printf("Type y or SP to resubscribe to %s.\n", ngname) FLUSH;
  857. X        ELSE
  858. X#endif
  859. X#ifdef TERSE
  860. X        fputs("y or SP to resubscribe.\n",stdout) FLUSH;
  861. X#endif
  862. X        fputs(ntoforget,stdout) FLUSH;
  863. X        goto reask_unsub;
  864. X    }
  865. X    else if (*buf == 'n' || *buf == 'q') {
  866. X        return FALSE;
  867. X    }
  868. X    else if (*buf == 'y') {
  869. X        rcchar[ng] = ':';
  870. X    }
  871. X    else {
  872. X        fputs(hforhelp,stdout) FLUSH;
  873. X        settle_down();
  874. X        goto reask_unsub;
  875. X    }
  876. X    }
  877. X
  878. X    /* now calculate how many unread articles in newsgroup */
  879. X
  880. X    set_toread(ng);
  881. X#ifdef RELOCATE
  882. X    if (do_reloc)
  883. X    ng = relocate_newsgroup(ng,-1);
  884. X#endif
  885. X    return toread[ng] >= TR_NONE;
  886. X}
  887. X
  888. X/* add a newsgroup to the .newsrc file (eventually) */
  889. X
  890. XNG_NUM
  891. Xadd_newsgroup(ngn, c)
  892. Xchar *ngn, c;
  893. X{
  894. X    register NG_NUM newng = nextrcline++;
  895. X                    /* increment max rcline index */
  896. X    
  897. X    rcnums[newng] = strlen(ngn) + 1;
  898. X    rcline[newng] = safemalloc((MEM_SIZE)(rcnums[newng] + 1));
  899. X    strcpy(rcline[newng],ngn);        /* and copy over the name */
  900. X    *(rcline[newng] + rcnums[newng]) = '\0';
  901. X    rcchar[newng] = c;            /* subscribe or unsubscribe */
  902. X    toread[newng] = TR_NONE;    /* just for prettiness */
  903. X#ifdef HASHNG
  904. X    sethash(newng);            /* so we can find it again */
  905. X#endif
  906. X#ifdef RELOCATE
  907. X    return c=='!' ? newng : relocate_newsgroup(newng,-1);
  908. X#else
  909. X    return newng;
  910. X#endif
  911. X}
  912. X
  913. X#ifdef RELOCATE
  914. XNG_NUM
  915. Xrelocate_newsgroup(ngx,newng)
  916. XNG_NUM ngx;
  917. XNG_NUM newng;
  918. X{
  919. X    char *dflt = (ngx!=current_ng ? "$^.L" : "$^L");
  920. X    char *tmprcline;
  921. X    ART_UNREAD tmptoread;
  922. X    char tmprcchar;
  923. X    char tmprcnums;
  924. X    ACT_POS tmpsoftptr;
  925. X    register NG_NUM i;
  926. X#if defined(DEBUGGING) && !defined(USETHREADS)
  927. X    ART_NUM tmpngmax;
  928. X#endif
  929. X#ifdef CACHEFIRST
  930. X    ART_NUM tmpabs1st;
  931. X#endif
  932. X    
  933. X    starthere = 0;                      /* Disable this optimization */
  934. X    writesoft = TRUE;            /* Update soft pointer file */
  935. X    if (ngx < nextrcline-1) {
  936. X#ifdef HASHNG
  937. X    for (i=0; i<HASHSIZ; i++) {
  938. X        if (hashtbl[i] > ngx)
  939. X        --hashtbl[i];
  940. X        else if (hashtbl[i] == ngx)
  941. X        hashtbl[i] = nextrcline-1;
  942. X    }
  943. X#endif
  944. X    tmprcline = rcline[ngx];
  945. X    tmptoread = toread[ngx];
  946. X    tmprcchar = rcchar[ngx];
  947. X    tmprcnums = rcnums[ngx];
  948. X    tmpsoftptr = softptr[ngx];
  949. X#if defined(DEBUGGING) && !defined(USETHREADS)
  950. X    tmpngmax = ngmax[ngx];
  951. X#endif
  952. X#ifdef CACHEFIRST
  953. X    tmpabs1st = abs1st[ngx];
  954. X#endif
  955. X    for (i=ngx+1; i<nextrcline; i++) {
  956. X        rcline[i-1] = rcline[i];
  957. X        toread[i-1] = toread[i];
  958. X        rcchar[i-1] = rcchar[i];
  959. X        rcnums[i-1] = rcnums[i];
  960. X        softptr[i-1] = softptr[i];
  961. X#if defined(DEBUGGING) && !defined(USETHREADS)
  962. X        ngmax[i-1] = ngmax[i];
  963. X#endif
  964. X#ifdef CACHEFIRST
  965. X        abs1st[i-1] = abs1st[i];
  966. X#endif
  967. X    }
  968. X    rcline[nextrcline-1] = tmprcline;
  969. X    toread[nextrcline-1] = tmptoread;
  970. X    rcchar[nextrcline-1] = tmprcchar;
  971. X    rcnums[nextrcline-1] = tmprcnums;
  972. X    softptr[nextrcline-1] = tmpsoftptr;
  973. X#if defined(DEBUGGING) && !defined(USETHREADS)
  974. X    ngmax[nextrcline-1] = tmpngmax;
  975. X#endif
  976. X#ifdef CACHEFIRST
  977. X    abs1st[nextrcline-1] = tmpabs1st;
  978. X#endif
  979. X    }
  980. X    if (current_ng > ngx)
  981. X    current_ng--;
  982. X    if (newng < 0) {
  983. X      reask_reloc:
  984. X    unflush_output();        /* disable any ^O in effect */
  985. X    if (addnewbydefault) {
  986. X        buf[0] = '$';
  987. X        buf[1] = '\0';
  988. X    } else {
  989. X#ifdef VERBOSE
  990. X    IF(verbose)
  991. X        printf("\nPut newsgroup where? [%s] ", dflt);
  992. X    ELSE
  993. X#endif
  994. X#ifdef TERSE
  995. X        printf("\nPut where? [%s] ", dflt);
  996. X#endif
  997. X    fflush(stdout);
  998. X      reinp_reloc:
  999. X    eat_typeahead();
  1000. X    getcmd(buf);
  1001. X    }
  1002. X    if (errno || *buf == '\f') {
  1003. X                /* if return from stop signal */
  1004. X        goto reask_reloc;    /* give them a prompt again */
  1005. X    }
  1006. X    setdef(buf,dflt);
  1007. X#ifdef VERIFY
  1008. X    printcmd();
  1009. X#endif
  1010. X    if (*buf == 'h') {
  1011. X#ifdef VERBOSE
  1012. X        IF(verbose) {
  1013. X        printf("\n\n\
  1014. XType ^ to put the newsgroup first (position 0).\n\
  1015. XType $ to put the newsgroup last (position %d).\n", nextrcline-1);
  1016. X        printf("\
  1017. XType . to put it before the current newsgroup (position %d).\n", current_ng);
  1018. X        printf("\
  1019. XType -newsgroup name to put it before that newsgroup.\n\
  1020. XType +newsgroup name to put it after that newsgroup.\n\
  1021. XType a number between 0 and %d to put it at that position.\n", nextrcline-1);
  1022. X        printf("\
  1023. XType L for a listing of newsgroups and their positions.\n") FLUSH;
  1024. X        }
  1025. X        ELSE
  1026. X#endif
  1027. X#ifdef TERSE
  1028. X        {
  1029. X        printf("\n\n\
  1030. X^ to put newsgroup first (pos 0).\n\
  1031. X$ to put last (pos %d).\n", nextrcline-1);
  1032. X        printf("\
  1033. X. to put before current newsgroup (pos %d).\n", current_ng);
  1034. X        printf("\
  1035. X-newsgroup to put before newsgroup.\n\
  1036. X+newsgroup to put after.\n\
  1037. Xnumber in 0-%d to put at that pos.\n", nextrcline-1);
  1038. X        printf("\
  1039. XL for list of .newsrc.\n") FLUSH;
  1040. X        }
  1041. X#endif
  1042. X        goto reask_reloc;
  1043. X    }
  1044. X    else if (*buf == 'L') {
  1045. X        putchar('\n') FLUSH;
  1046. X        list_newsgroups();
  1047. X        goto reask_reloc;
  1048. X    }
  1049. X    else if (isdigit(*buf)) {
  1050. X        if (!finish_command(TRUE))    /* get rest of command */
  1051. X        goto reinp_reloc;
  1052. X        newng = atol(buf);
  1053. X        if (newng < 0)
  1054. X        newng = 0;
  1055. X        if (newng >= nextrcline)
  1056. X        return nextrcline-1;
  1057. X    }
  1058. X    else if (*buf == '^') {
  1059. X        putchar('\n') FLUSH;
  1060. X        newng = 0;
  1061. X    }
  1062. X    else if (*buf == '$') {
  1063. X        if (! addnewbydefault) putchar('\n') FLUSH;
  1064. X        return nextrcline-1;
  1065. X    }
  1066. X    else if (*buf == '.') {
  1067. X        putchar('\n') FLUSH;
  1068. X        newng = current_ng;
  1069. X    }
  1070. X    else if (*buf == '-' || *buf == '+') {
  1071. X        if (!finish_command(TRUE))    /* get rest of command */
  1072. X        goto reinp_reloc;
  1073. X        newng = find_ng(buf+1);
  1074. X        if (newng == nextrcline) {
  1075. X        fputs("Not found.",stdout) FLUSH;
  1076. X        goto reask_reloc;
  1077. X        }
  1078. X        if (*buf == '+')
  1079. X        newng++;
  1080. X    }
  1081. X    else {
  1082. X        printf("\n%s",hforhelp) FLUSH;
  1083. X        settle_down();
  1084. X        goto reask_reloc;
  1085. X    }
  1086. X    }
  1087. X    if (newng < nextrcline-1) {
  1088. X#ifdef HASHNG
  1089. X    for (i=0; i<HASHSIZ; i++) {
  1090. X        if (hashtbl[i] == nextrcline-1)
  1091. X        hashtbl[i] = newng;
  1092. X        else if (hashtbl[i] >= newng)
  1093. X        ++hashtbl[i];
  1094. X    }
  1095. X#endif
  1096. X    tmprcline = rcline[nextrcline-1];
  1097. X    tmptoread = toread[nextrcline-1];
  1098. X    tmprcchar = rcchar[nextrcline-1];
  1099. X    tmprcnums = rcnums[nextrcline-1];
  1100. X    tmpsoftptr = softptr[nextrcline-1];
  1101. X#if defined(DEBUGGING) && !defined(USETHREADS)
  1102. X    tmpngmax = ngmax[nextrcline-1];
  1103. X#endif
  1104. X#ifdef CACHEFIRST
  1105. X    tmpabs1st = abs1st[nextrcline-1];
  1106. X#endif
  1107. X    for (i=nextrcline-2; i>=newng; i--) {
  1108. X        rcline[i+1] = rcline[i];
  1109. X        toread[i+1] = toread[i];
  1110. X        rcchar[i+1] = rcchar[i];
  1111. X        rcnums[i+1] = rcnums[i];
  1112. X        softptr[i+1] = softptr[i];
  1113. X#if defined(DEBUGGING) && !defined(USETHREADS)
  1114. X        ngmax[i+1] = ngmax[i];
  1115. X#endif
  1116. X#ifdef CACHEFIRST
  1117. X        abs1st[i+1] = abs1st[i];
  1118. X#endif
  1119. X    }
  1120. X    rcline[newng] = tmprcline;
  1121. X    toread[newng] = tmptoread;
  1122. X    rcchar[newng] = tmprcchar;
  1123. X    rcnums[newng] = tmprcnums;
  1124. X    softptr[newng] = tmpsoftptr;
  1125. X#if defined(DEBUGGING) && !defined(USETHREADS)
  1126. X    ngmax[newng] = tmpngmax;
  1127. X#endif
  1128. X#ifdef CACHEFIRST
  1129. X    abs1st[newng] = tmpabs1st;
  1130. X#endif
  1131. X    }
  1132. X    if (current_ng >= newng)
  1133. X    current_ng++;
  1134. X    return newng;
  1135. X}
  1136. X#endif
  1137. X
  1138. X/* List out the newsrc with annotations */
  1139. X
  1140. Xvoid
  1141. Xlist_newsgroups()
  1142. X{
  1143. X    register NG_NUM i;
  1144. X    char tmpbuf[2048];
  1145. X    static char *status[] = {"(READ)","(UNSUB)","(BOGUS)","(JUNK)"};
  1146. X    int cmd;
  1147. X
  1148. X    page_init();
  1149. X    print_lines("\
  1150. X  #  Status  Newsgroup\n\
  1151. X",STANDOUT);
  1152. X    for (i=0; i<nextrcline && !int_count; i++) {
  1153. X    if (toread[i] >= 0)
  1154. X        set_toread(i);
  1155. X    *(rcline[i] + rcnums[i] - 1) = rcchar[i];
  1156. X    if (toread[i] > 0)
  1157. X        sprintf(tmpbuf,"%3d %6ld   ",i,(long)toread[i]);
  1158. X    else
  1159. X        sprintf(tmpbuf,"%3d %7s  ",i,status[-toread[i]]);
  1160. X    safecpy(tmpbuf+13,rcline[i],2034);
  1161. X    *(rcline[i] + rcnums[i] - 1) = '\0';
  1162. X    if (cmd = print_lines(tmpbuf,NOMARKING)) {
  1163. X        if (cmd > 0)
  1164. X        pushchar(cmd);
  1165. X        break;
  1166. X    }
  1167. X    }
  1168. X    int_count = 0;
  1169. X}
  1170. X
  1171. X/* find a newsgroup in .newsrc */
  1172. X
  1173. XNG_NUM
  1174. Xfind_ng(ngnam)
  1175. Xchar *ngnam;
  1176. X{
  1177. X    register NG_NUM ngnum;
  1178. X#ifdef HASHNG
  1179. X    register int hashix = hash(ngnam);
  1180. X    register int incr = 1;
  1181. X
  1182. X    while ((ngnum = hashtbl[hashix]) >= 0) {
  1183. X    if (strEQ(rcline[ngnum], ngnam) && toread[ngnum] >= TR_UNSUB)
  1184. X        return ngnum;
  1185. X    hashix = (hashix + incr) % HASHSIZ;
  1186. X    incr += 2;            /* offsets from original are in n*2 */
  1187. X    }
  1188. X    return nextrcline;            /* = notfound */
  1189. X
  1190. X#else /* just do linear search */
  1191. X
  1192. X    for (ngnum = 0; ngnum < nextrcline; ngnum++) {
  1193. X    if (strEQ(rcline[ngnum],ngnam))
  1194. X        break;
  1195. X    }
  1196. X    return ngnum;
  1197. X#endif
  1198. X}
  1199. X
  1200. Xvoid
  1201. Xcleanup_rc()
  1202. X{
  1203. X    register NG_NUM ngx;
  1204. X    register NG_NUM bogosity = 0;
  1205. X
  1206. X#ifdef VERBOSE
  1207. X    IF(verbose)
  1208. X    fputs("Checking out your .newsrc--hang on a second...\n",stdout)
  1209. X      FLUSH;
  1210. X    ELSE
  1211. X#endif
  1212. X#ifdef TERSE
  1213. X    fputs("Checking .newsrc--hang on...\n",stdout) FLUSH;
  1214. X#endif
  1215. X    for (ngx = 0; ngx < nextrcline; ngx++) {
  1216. X    if (toread[ngx] >= TR_UNSUB) {
  1217. X        set_toread(ngx);        /* this may reset newsgroup */
  1218. X                    /* or declare it bogus */
  1219. X    }
  1220. X    if (toread[ngx] == TR_BOGUS)
  1221. X        bogosity++;
  1222. X    }
  1223. X    for (ngx = nextrcline-1; ngx >= 0 && toread[ngx] == TR_BOGUS; ngx--)
  1224. X    bogosity--;            /* discount already moved ones */
  1225. X    if (nextrcline > 5 && bogosity > nextrcline / 2) {
  1226. X    fputs(
  1227. X"It looks like the active file is messed up.  Contact your news administrator,\n\
  1228. X",stdout);
  1229. X    fputs(
  1230. X"leave the \"bogus\" groups alone, and they may come back to normal.  Maybe.\n\
  1231. X",stdout) FLUSH;
  1232. X    }
  1233. X#ifdef RELOCATE
  1234. X    else if (bogosity) {
  1235. X#ifdef VERBOSE
  1236. X    IF(verbose)
  1237. X        fputs("Moving bogus newsgroups to the end of your .newsrc.\n",
  1238. X        stdout) FLUSH;
  1239. X    ELSE
  1240. X#endif
  1241. X#ifdef TERSE
  1242. X        fputs("Moving boguses to the end.\n",stdout) FLUSH;
  1243. X#endif
  1244. X    for (; ngx >= 0; ngx--) {
  1245. X        if (toread[ngx] == TR_BOGUS)
  1246. X        relocate_newsgroup(ngx,nextrcline-1);
  1247. X    }
  1248. X#ifdef DELBOGUS
  1249. Xreask_bogus:
  1250. X    in_char("Delete bogus newsgroups? [ny] ", 'D');
  1251. X    setdef(buf,"n");
  1252. X#ifdef VERIFY
  1253. X    printcmd();
  1254. X#endif
  1255. X    putchar('\n') FLUSH;
  1256. X    if (*buf == 'h') {
  1257. X#ifdef VERBOSE
  1258. X        IF(verbose)
  1259. X        fputs("\
  1260. XType y to delete bogus newsgroups.\n\
  1261. XType n or SP to leave them at the end in case they return.\n\
  1262. X",stdout) FLUSH;
  1263. X        ELSE
  1264. X#endif
  1265. X#ifdef TERSE
  1266. X        fputs("y to delete, n to keep\n",stdout) FLUSH;
  1267. X#endif
  1268. X        goto reask_bogus;
  1269. X    }
  1270. X    else if (*buf == 'n' || *buf == 'q')
  1271. X        ;
  1272. X    else if (*buf == 'y') {
  1273. X        while (toread[nextrcline-1] == TR_BOGUS && nextrcline > 0)
  1274. X        --nextrcline;        /* real tough, huh? */
  1275. X    }
  1276. X    else {
  1277. X        fputs(hforhelp,stdout) FLUSH;
  1278. X        settle_down();
  1279. X        goto reask_bogus;
  1280. X    }
  1281. X#endif
  1282. X    }
  1283. X#else
  1284. X#ifdef VERBOSE
  1285. X    IF(verbose)
  1286. X    fputs("You should edit bogus newsgroups out of your .newsrc.\n",
  1287. X        stdout) FLUSH;
  1288. X    ELSE
  1289. X#endif
  1290. X#ifdef TERSE
  1291. X    fputs("Edit boguses from .newsrc.\n",stdout) FLUSH;
  1292. X#endif
  1293. X#endif
  1294. X    paranoid = FALSE;
  1295. X}
  1296. X
  1297. X#ifdef HASHNG
  1298. X/* make an entry in the hash table for the current newsgroup */
  1299. X
  1300. Xvoid
  1301. Xsethash(thisng)
  1302. XNG_NUM thisng;
  1303. X{
  1304. X    register int hashix = hash(rcline[thisng]);
  1305. X    register int incr = 1;
  1306. X#ifdef DEBUGGING
  1307. X    static int hashhits = 0, hashtries = 0;
  1308. X#endif
  1309. X
  1310. X#ifdef DEBUGGING
  1311. X    hashtries++;
  1312. X#endif
  1313. X    while (hashtbl[hashix] >= 0) {
  1314. X#ifdef DEBUGGING
  1315. X    hashhits++;
  1316. X    if (debug & DEB_HASH) {
  1317. X        printf("  Hash hits: %d / %d\n",hashhits, hashtries) FLUSH;
  1318. X    }
  1319. X    hashtries++;
  1320. X#endif
  1321. X    hashix = (hashix + incr) % HASHSIZ;
  1322. X    incr += 2;            /* offsets from original are in n*2 */
  1323. X    }
  1324. X    hashtbl[hashix] = thisng;
  1325. X}
  1326. X
  1327. Xshort prime[] = {1,2,-3,-5,7,11,-13,-17,19,23,-29,-31,37,41,-43,-47,53,57,-59,
  1328. X    -61,67,71,-73,-79,83,89,-97,-101,1,1,1,1,1,1,1,1,1,1,1,1};
  1329. X
  1330. Xint
  1331. Xhash(ngnam)
  1332. Xregister char *ngnam;
  1333. X{
  1334. X    register int i = 0;
  1335. X    register int ch;
  1336. X    register int sum = 0;
  1337. X#ifdef DEBUGGING
  1338. X    char *ngn = ngnam;
  1339. X#endif
  1340. X
  1341. X    while (ch = *ngnam++) {
  1342. X    sum += (ch + i) * prime[i];   /* gives ~ 10% hits at 25% full */
  1343. X    i++;
  1344. X    }
  1345. X#ifdef DEBUGGING
  1346. X    if (debug & DEB_HASH)
  1347. X    printf("hash(%s) => %d => %d\n",ngn, sum, (sum<0?-sum:sum)%HASHSIZ)
  1348. X      FLUSH;
  1349. X#endif
  1350. X    if (sum < 0)
  1351. X    sum = -sum;
  1352. X    return sum % HASHSIZ;
  1353. X}
  1354. X
  1355. X#endif
  1356. X
  1357. Xvoid
  1358. Xnewsrc_check()
  1359. X{
  1360. X    rcfp = fopen(rcname,"r");        /* open it */
  1361. X    if (rcfp == Nullfp) {            /* not there? */
  1362. X#ifdef VERBOSE
  1363. X    IF(verbose)
  1364. X        fputs("\nTrying to set up a .newsrc file--running newsetup...\n\n\
  1365. X",stdout) FLUSH;
  1366. X    ELSE
  1367. X#endif
  1368. X#ifdef TERSE
  1369. X        fputs("Setting up .newsrc...\n",stdout) FLUSH;
  1370. X#endif
  1371. X    if (doshell(sh,filexp(NEWSETUP)) ||
  1372. X        (rcfp = fopen(rcname,"r")) == Nullfp) {
  1373. X#ifdef VERBOSE
  1374. X        IF(verbose)
  1375. X        fputs("\nCan't create a .newsrc--you must do it yourself.\n\
  1376. X",stdout) FLUSH;
  1377. X        ELSE
  1378. X#endif
  1379. X#ifdef TERSE
  1380. X        fputs("(Fatal)\n",stdout) FLUSH;
  1381. X#endif
  1382. X        finalize(1);
  1383. X    }
  1384. X    }
  1385. X    else {
  1386. X    UNLINK(rcbname);        /* unlink backup file name */
  1387. X    link(rcname,rcbname);        /* and backup current name */
  1388. X    }
  1389. X}
  1390. X
  1391. X/* write out the (presumably) revised .newsrc */
  1392. X
  1393. Xvoid
  1394. Xwrite_rc()
  1395. X{
  1396. X    register NG_NUM tmpng;
  1397. X    register char *delim;
  1398. X
  1399. X    rcfp = fopen(rctname, "w");        /* open .newsrc */
  1400. X    if (rcfp == Nullfp) {
  1401. X    printf("Can't recreate .newsrc\n") FLUSH;
  1402. X    finalize(1);
  1403. X    }
  1404. X
  1405. X    /* write out each line*/
  1406. X
  1407. X    for (tmpng = 0; tmpng < nextrcline; tmpng++) {
  1408. X    if (rcnums[tmpng]) {
  1409. X        delim = rcline[tmpng] + rcnums[tmpng] - 1;
  1410. X        *delim = rcchar[tmpng];
  1411. X    }
  1412. X    else
  1413. X        delim = Nullch;
  1414. X#ifdef DEBUGGING
  1415. X    if (debug & DEB_NEWSRC_LINE)
  1416. X        printf("%s\n",rcline[tmpng]) FLUSH;
  1417. X#endif
  1418. X    if (fprintf(rcfp,"%s\n",rcline[tmpng]) < 0){
  1419. X            printf("Can't recreate .newsrc\n") FLUSH;
  1420. X            fclose(rcfp);            /* close .newsrc */
  1421. X            UNLINK(rctname);
  1422. X            finalize(1);
  1423. X            }
  1424. X
  1425. X            ;
  1426. X    if (delim)
  1427. X        *delim = '\0';        /* might still need this line */
  1428. X    }
  1429. X
  1430. X    fclose(rcfp);            /* close .newsrc */
  1431. X    UNLINK(rcname);
  1432. X    link(rctname,rcname);
  1433. X    UNLINK(rctname);
  1434. X
  1435. X    if (writesoft) {
  1436. X    tmpfp = fopen(filexp(softname), "w");    /* open .rnsoft */
  1437. X    if (tmpfp == Nullfp) {
  1438. X        printf(cantcreate,filexp(softname)) FLUSH;
  1439. X        return;
  1440. X    }
  1441. X    for (tmpng = 0; tmpng < nextrcline; tmpng++) {
  1442. X        fprintf(tmpfp,"%ld\n",(long)softptr[tmpng]);
  1443. X    }
  1444. X    fclose(tmpfp);
  1445. X    }
  1446. X}
  1447. X
  1448. Xvoid
  1449. Xget_old_rc()
  1450. X{
  1451. X    UNLINK(rctname);
  1452. X#ifdef RENAME
  1453. X    rename(rcname,rctname);
  1454. X    rename(rcbname,rcname);
  1455. X#else
  1456. X    link(rcname,rctname);
  1457. X    UNLINK(rcname);
  1458. X    link(rcbname,rcname);
  1459. X    UNLINK(rcbname);
  1460. X#endif
  1461. X}
  1462. END_OF_FILE
  1463.   if test 25009 -ne `wc -c <'rcstuff.c'`; then
  1464.     echo shar: \"'rcstuff.c'\" unpacked with wrong size!
  1465.   fi
  1466.   # end of 'rcstuff.c'
  1467. fi
  1468. if test -f 'term.c' -a "${1}" != "-c" ; then 
  1469.   echo shar: Will not clobber existing file \"'term.c'\"
  1470. else
  1471.   echo shar: Extracting \"'term.c'\" \(25986 characters\)
  1472.   sed "s/^X//" >'term.c' <<'END_OF_FILE'
  1473. X/* $Header: term.c,v 4.3.3.2 91/01/16 03:38:36 davison Trn $
  1474. X *
  1475. X * $Log:    term.c,v $
  1476. X * Revision 4.3.3.2  91/01/16  03:38:36  davison
  1477. X * Integrated rn patches 48-54.  Revised 8-bit character support.
  1478. X * 
  1479. X * Revision 4.3.3.1  90/07/28  18:09:09  davison
  1480. X * Initial Trn Release
  1481. X * 
  1482. X * Revision 4.3.2.13  90/12/12  03:03:28  sob
  1483. X * Lost a closing paren in circfill()
  1484. X * 
  1485. X * Revision 4.3.2.12  90/12/10  01:33:54  sob
  1486. X * First attempts to make rn "8 bit clean"
  1487. X * 
  1488. X * Revision 4.3.2.11  90/11/22  13:34:06  sob
  1489. X * Added a change to circfill to make it work with POSIX-compliant OSes.
  1490. X * 
  1491. X * Revision 4.3.2.10  90/11/05  23:41:29  sob
  1492. X * Now it's gone.
  1493. X * 
  1494. X * Revision 4.3.2.9  90/11/05  23:30:07  sob
  1495. X * moved the winsize struct in anticipation of removing it.
  1496. X * 
  1497. X * Revision 4.3.2.8  90/10/01  01:43:59  sob
  1498. X * Fixed syntax error pointed out by stealth@m-net.ann-arbor.mi.us.
  1499. X * 
  1500. X * Revision 4.3.2.7  90/04/21  16:54:29  sob
  1501. X * Installed patches provided by SCO for SCO Xenix
  1502. X * 
  1503. X * Revision 4.3.2.6  90/04/13  23:48:17  sob
  1504. X * Modifications provided by Gene Hackney for 3b2.
  1505. X * 
  1506. X * Revision 4.3.2.5  90/04/06  20:35:08  sob
  1507. X * Added fixes for SCO Xenix sent by ronald@robobar.co.uk.
  1508. X * 
  1509. X * Revision 4.3.2.4  90/03/22  23:05:38  sob
  1510. X * Fixes provided by Wayne Davison <drivax!davison>
  1511. X * 
  1512. X * Revision 4.3.2.3  89/11/28  01:51:58  sob
  1513. X * Now handles SIGWINCH correctly.
  1514. X * 
  1515. X * Revision 4.3.2.2  89/11/27  01:31:34  sob
  1516. X * Altered NNTP code per ideas suggested by Bela Lubkin
  1517. X * <filbo@gorn.santa-cruz.ca.us>
  1518. X * 
  1519. X * Revision 4.3.2.1  89/11/06  01:02:12  sob
  1520. X * Added RRN support from NNTP 1.5
  1521. X * 
  1522. X * Revision 4.3.1.3  85/09/10  11:05:23  lwall
  1523. X * Improved %m in in_char().
  1524. X * 
  1525. X * Revision 4.3.1.2  85/05/16  16:45:35  lwall
  1526. X * Forced \r to \n on input.
  1527. X * Fix for terminfo braindamage regarding bc emulation.
  1528. X * 
  1529. X * Revision 4.3.1.1  85/05/10  11:41:03  lwall
  1530. X * Branch for patches.
  1531. X * 
  1532. X * Revision 4.3  85/05/01  11:51:10  lwall
  1533. X * Baseline for release with 4.3bsd.
  1534. X * 
  1535. X */
  1536. X
  1537. X#include "EXTERN.h"
  1538. X#include "common.h"
  1539. X#include "util.h"
  1540. X#include "final.h"
  1541. X#include "help.h"
  1542. X#include "cheat.h"
  1543. X#include "intrp.h"
  1544. X#include "INTERN.h"
  1545. X#include "term.h"
  1546. X
  1547. Xchar ERASECH;        /* rubout character */
  1548. Xchar KILLCH;        /* line delete character */
  1549. Xchar tcarea[TCSIZE];    /* area for "compiled" termcap strings */
  1550. X
  1551. X#ifdef USETHREADS
  1552. Xint upcost;
  1553. X#endif
  1554. X
  1555. X/* guarantee capability pointer != Nullch */
  1556. X/* (I believe terminfo will ignore the &tmpaddr argument.) */
  1557. X
  1558. X#define Tgetstr(key) ((tmpstr = tgetstr(key,&tmpaddr)) ? tmpstr : nullstr)
  1559. X
  1560. X#ifdef PUSHBACK
  1561. Xstruct keymap {
  1562. X    char km_type[128];
  1563. X    union km_union {
  1564. X    struct keymap *km_km;
  1565. X    char *km_str;
  1566. X    } km_ptr[128];
  1567. X};
  1568. X
  1569. X#define KM_NOTHIN 0
  1570. X#define KM_STRING 1
  1571. X#define KM_KEYMAP 2
  1572. X#define KM_BOGUS 3
  1573. X
  1574. X#define KM_TMASK 3
  1575. X#define KM_GSHIFT 4
  1576. X#define KM_GMASK 7
  1577. X
  1578. Xtypedef struct keymap KEYMAP;
  1579. X
  1580. XKEYMAP *topmap INIT(Null(KEYMAP*));
  1581. X
  1582. Xvoid mac_init();
  1583. XKEYMAP *newkeymap();
  1584. Xvoid show_keymap();
  1585. Xvoid pushstring();
  1586. X#endif
  1587. X
  1588. Xvoid line_col_calcs();
  1589. X
  1590. X/* terminal initialization */
  1591. X
  1592. Xvoid
  1593. Xterm_init()
  1594. X{
  1595. X    savetty();                /* remember current tty state */
  1596. X
  1597. X#ifdef TERMIO
  1598. X    ospeed = _tty.c_cflag & CBAUD;    /* for tputs() */
  1599. X    ERASECH = _tty.c_cc[VERASE];    /* for finish_command() */
  1600. X    KILLCH = _tty.c_cc[VKILL];        /* for finish_command() */
  1601. X#else
  1602. X    ospeed = _tty.sg_ospeed;        /* for tputs() */
  1603. X    ERASECH = _tty.sg_erase;        /* for finish_command() */
  1604. X    KILLCH = _tty.sg_kill;        /* for finish_command() */
  1605. X#endif
  1606. X
  1607. X    /* The following could be a table but I can't be sure that there isn't */
  1608. X    /* some degree of sparsity out there in the world. */
  1609. X
  1610. X    switch (ospeed) {            /* 1 second of padding */
  1611. X#ifdef BEXTA
  1612. X        case BEXTA:  just_a_sec = 1920; break;
  1613. X#else
  1614. X#ifdef B19200
  1615. X        case B19200: just_a_sec = 1920; break;
  1616. X#endif
  1617. X#endif
  1618. X        case B9600:  just_a_sec =  960; break;
  1619. X        case B4800:  just_a_sec =  480; break;
  1620. X        case B2400:  just_a_sec =  240; break;
  1621. X        case B1800:  just_a_sec =  180; break;
  1622. X        case B1200:  just_a_sec =  120; break;
  1623. X        case B600:   just_a_sec =   60; break;
  1624. X    case B300:   just_a_sec =   30; break;
  1625. X    /* do I really have to type the rest of this??? */
  1626. X        case B200:   just_a_sec =   20; break;
  1627. X        case B150:   just_a_sec =   15; break;
  1628. X        case B134:   just_a_sec =   13; break;
  1629. X        case B110:   just_a_sec =   11; break;
  1630. X        case B75:    just_a_sec =    8; break;
  1631. X        case B50:    just_a_sec =    5; break;
  1632. X        default:     just_a_sec =  960; break;
  1633. X                    /* if we are running detached I */
  1634. X    }                    /*  don't want to know about it! */
  1635. X}
  1636. X
  1637. X/* set terminal characteristics */
  1638. X
  1639. Xvoid
  1640. Xterm_set(tcbuf)
  1641. Xchar *tcbuf;        /* temp area for "uncompiled" termcap entry */
  1642. X{
  1643. X    char *tmpaddr;            /* must not be register */
  1644. X    register char *tmpstr;
  1645. X    char *tgetstr();
  1646. X    char *s;
  1647. X    int status;
  1648. X#ifdef TIOCGWINSZ
  1649. X    struct winsize winsize;
  1650. X#endif
  1651. X
  1652. X#ifdef PENDING
  1653. X#if ! defined (FIONREAD) && ! defined (RDCHK)
  1654. X    /* do no delay reads on something that always gets closed on exit */
  1655. X
  1656. X    devtty = open("/dev/tty",0);
  1657. X    if (devtty < 0) {
  1658. X    printf(cantopen,"/dev/tty") FLUSH;
  1659. X    finalize(1);
  1660. X    }
  1661. X    fcntl(devtty,F_SETFL,O_NDELAY);
  1662. X#endif
  1663. X#endif
  1664. X    
  1665. X    /* get all that good termcap stuff */
  1666. X
  1667. X#ifdef HAVETERMLIB
  1668. X    status = tgetent(tcbuf,getenv("TERM"));    /* get termcap entry */
  1669. X    if (status < 1) {
  1670. X#ifdef VERBOSE
  1671. X    printf("No termcap %s found.\n", status ? "file" : "entry") FLUSH;
  1672. X#else
  1673. X    fputs("Termcap botch\n",stdout) FLUSH;
  1674. X#endif
  1675. X    finalize(1);
  1676. X    }
  1677. X    tmpaddr = tcarea;            /* set up strange tgetstr pointer */
  1678. X    s = Tgetstr("pc");            /* get pad character */
  1679. X    PC = *s;                /* get it where tputs wants it */
  1680. X    if (!tgetflag("bs")) {        /* is backspace not used? */
  1681. X    BC = Tgetstr("bc");        /* find out what is */
  1682. X    if (BC == nullstr)         /* terminfo grok's 'bs' but not 'bc' */
  1683. X        BC = Tgetstr("le");
  1684. X    } else
  1685. X    BC = "\b";            /* make a backspace handy */
  1686. X    UP = Tgetstr("up");            /* move up a line */
  1687. X    if (!*UP)                /* no UP string? */
  1688. X    marking = 0;            /* disable any marking */
  1689. X    if (muck_up_clear)            /* this is for weird HPs */
  1690. X    CL = "\n\n\n\n";
  1691. X    else
  1692. X    CL = Tgetstr("cl");        /* get clear string */
  1693. X    CE = Tgetstr("ce");            /* clear to end of line string */
  1694. X#if defined(CLEAREOL) || defined(USETHREADS)
  1695. X    HO = Tgetstr("ho");            /* home cursor if no CM */
  1696. X    CM = Tgetstr("cm");            /* cursor motion */
  1697. X    if (*CM || *HO)
  1698. X    can_home = TRUE;
  1699. X#endif
  1700. X#ifdef CLEAREOL
  1701. X    CD = Tgetstr("cd");            /* clear to end of display */
  1702. X    if (!*CE || !*CD || !can_home)    /* can we CE, CD, and home? */
  1703. X    can_home_clear = FALSE;        /*  no, so disable use of clear eol */
  1704. X    if (!*CE) CE = CD;
  1705. X#endif /* CLEAREOL */
  1706. X#ifdef USETHREADS
  1707. X    upcost = strlen(UP);
  1708. X#endif
  1709. X    SO = Tgetstr("so");            /* begin standout */
  1710. X    SE = Tgetstr("se");            /* end standout */
  1711. X    if ((SG = tgetnum("sg"))<0)
  1712. X    SG = 0;                /* blanks left by SG, SE */
  1713. X    US = Tgetstr("us");            /* start underline */
  1714. X    UE = Tgetstr("ue");            /* end underline */
  1715. X    if ((UG = tgetnum("ug"))<0)
  1716. X    UG = 0;                /* blanks left by US, UE */
  1717. X    if (*US)
  1718. X    UC = nullstr;            /* UC must not be NULL */
  1719. X    else
  1720. X    UC = Tgetstr("uc");        /* underline a character */
  1721. X    if (!*US && !*UC) {            /* no underline mode? */
  1722. X    US = SO;            /* substitute standout mode */
  1723. X    UE = SE;
  1724. X    UG = SG;
  1725. X    }
  1726. X    LINES = tgetnum("li");        /* lines per page */
  1727. X    COLS = tgetnum("co");        /* columns on page */
  1728. X
  1729. X#ifdef TIOCGWINSZ
  1730. X    { struct winsize ws;
  1731. X    if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) {
  1732. X        LINES = ws.ws_row;
  1733. X        COLS = ws.ws_col;
  1734. X    }
  1735. X    }
  1736. X#endif
  1737. X    
  1738. X    AM = tgetflag("am");        /* terminal wraps automatically? */
  1739. X    XN = tgetflag("xn");        /* then eats next newline? */
  1740. X    VB = Tgetstr("vb");
  1741. X    if (!*VB)
  1742. X    VB = "\007";
  1743. X    CR = Tgetstr("cr");
  1744. X    if (!*CR) {
  1745. X    if (tgetflag("nc") && *UP) {
  1746. X        CR = safemalloc((MEM_SIZE)strlen(UP)+2);
  1747. X        sprintf(CR,"%s\r",UP);
  1748. X    }
  1749. X    else
  1750. X        CR = "\r";
  1751. X    }
  1752. X#ifdef TIOCGWINSZ
  1753. X    if (ioctl(1, TIOCGWINSZ, &winsize)>=0) {
  1754. X        if (winsize.ws_row>0) LINES=winsize.ws_row;
  1755. X        if (winsize.ws_col>0) COLS=winsize.ws_col;
  1756. X    }
  1757. X#endif
  1758. X#else
  1759. X    ??????                /* Roll your own... */
  1760. X#endif
  1761. X    line_col_calcs();
  1762. X    noecho();                /* turn off echo */
  1763. X    crmode();                /* enter cbreak mode */
  1764. X
  1765. X#ifdef PUSHBACK
  1766. X    mac_init(tcbuf);
  1767. X#endif
  1768. X}
  1769. X
  1770. X#ifdef PUSHBACK
  1771. Xvoid
  1772. Xmac_init(tcbuf)
  1773. Xchar *tcbuf;
  1774. X{
  1775. X    char tmpbuf[1024];
  1776. X
  1777. X    tmpfp = fopen(filexp(getval("RNMACRO",RNMACRO)),"r");
  1778. X    if (tmpfp != Nullfp) {
  1779. X    while (fgets(tcbuf,1024,tmpfp) != Nullch) {
  1780. X        mac_line(tcbuf,tmpbuf,(sizeof tmpbuf));
  1781. X    }
  1782. X    fclose(tmpfp);
  1783. X    }
  1784. X}
  1785. X
  1786. Xvoid
  1787. Xmac_line(line,tmpbuf,tbsize)
  1788. Xchar *line;
  1789. Xchar *tmpbuf;
  1790. Xint tbsize;
  1791. X{
  1792. X    register char *s, *m;
  1793. X    register KEYMAP *curmap;
  1794. X    register int ch;
  1795. X    register int garbage = 0;
  1796. X    static char override[] = "\nkeymap overrides string\n";
  1797. X
  1798. X    if (topmap == Null(KEYMAP*))
  1799. X    topmap = newkeymap();
  1800. X    if (*line == '#' || *line == '\n')
  1801. X    return;
  1802. X    if (line[ch = strlen(line)-1] == '\n')
  1803. X    line[ch] = '\0';
  1804. X    m = dointerp(tmpbuf,tbsize,line," \t");
  1805. X    if (!*m)
  1806. X    return;
  1807. X    while (*m == ' ' || *m == '\t') m++;
  1808. X    for (s=tmpbuf,curmap=topmap; *s; s++) {
  1809. X    ch = *s & 0177;
  1810. X    if (s[1] == '+' && isdigit(s[2])) {
  1811. X        s += 2;
  1812. X        garbage = (*s & KM_GMASK) << KM_GSHIFT;
  1813. X    }
  1814. X    else
  1815. X        garbage = 0;
  1816. X    if (s[1]) {
  1817. X        if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) {
  1818. X        fputs(override,stdout) FLUSH;
  1819. X        free(curmap->km_ptr[ch].km_str);
  1820. X        curmap->km_ptr[ch].km_str = Nullch;
  1821. X        }
  1822. X        curmap->km_type[ch] = KM_KEYMAP + garbage;
  1823. X        if (curmap->km_ptr[ch].km_km == Null(KEYMAP*))
  1824. X        curmap->km_ptr[ch].km_km = newkeymap();
  1825. X        curmap = curmap->km_ptr[ch].km_km;
  1826. X    }
  1827. X    else {
  1828. X        if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP)
  1829. X        fputs(override,stdout) FLUSH;
  1830. X        else {
  1831. X        curmap->km_type[ch] = KM_STRING + garbage;
  1832. X        curmap->km_ptr[ch].km_str = savestr(m);
  1833. X        }
  1834. X    }
  1835. X    }
  1836. X}
  1837. X
  1838. XKEYMAP*
  1839. Xnewkeymap()
  1840. X{
  1841. X    register int i;
  1842. X    register KEYMAP *map;
  1843. X
  1844. X#ifndef lint
  1845. X    map = (KEYMAP*)safemalloc(sizeof(KEYMAP));
  1846. X#else
  1847. X    map = Null(KEYMAP*);
  1848. X#endif /* lint */
  1849. X    for (i=127; i>=0; --i) {
  1850. X    map->km_ptr[i].km_km = Null(KEYMAP*);
  1851. X    map->km_type[i] = KM_NOTHIN;
  1852. X    }
  1853. X    return map;
  1854. X}
  1855. X
  1856. Xvoid
  1857. Xshow_macros()
  1858. X{
  1859. X    char prebuf[64];
  1860. X
  1861. X    if (topmap != Null(KEYMAP*)) {
  1862. X    print_lines("Macros:\n",STANDOUT);
  1863. X    *prebuf = '\0';
  1864. X    show_keymap(topmap,prebuf);
  1865. X    }
  1866. X    else {
  1867. X    print_lines("No macros defined.\n", NOMARKING);
  1868. X    }
  1869. X}
  1870. X
  1871. Xvoid
  1872. Xshow_keymap(curmap,prefix)
  1873. Xregister KEYMAP *curmap;
  1874. Xchar *prefix;
  1875. X{
  1876. X    register int i;
  1877. X    register char *next = prefix + strlen(prefix);
  1878. X    register int kt;
  1879. X
  1880. X    for (i=0; i<128; i++) {
  1881. X    if (kt = curmap->km_type[i]) {
  1882. X        if (i < ' ')
  1883. X        sprintf(next,"^%c",i+64);
  1884. X        else if (i == ' ')
  1885. X        strcpy(next,"\\040");
  1886. X        else if (i == 127)
  1887. X        strcpy(next,"^?");
  1888. X        else
  1889. X        sprintf(next,"%c",i);
  1890. X        if ((kt >> KM_GSHIFT) & KM_GMASK) {
  1891. X        sprintf(cmd_buf,"+%d", (kt >> KM_GSHIFT) & KM_GMASK);
  1892. X        strcat(next,cmd_buf);
  1893. X        }
  1894. X        switch (kt & KM_TMASK) {
  1895. X        case KM_NOTHIN:
  1896. X        sprintf(cmd_buf,"%s    %c\n",prefix,i);
  1897. X        print_lines(cmd_buf,NOMARKING);
  1898. X        break;
  1899. X        case KM_KEYMAP:
  1900. X        show_keymap(curmap->km_ptr[(char)i].km_km, prefix);
  1901. X        break;
  1902. X        case KM_STRING:
  1903. X        sprintf(cmd_buf,"%s    %s\n",prefix,curmap->km_ptr[i].km_str);
  1904. X        print_lines(cmd_buf,NOMARKING);
  1905. X        break;
  1906. X        case KM_BOGUS:
  1907. X        sprintf(cmd_buf,"%s    BOGUS\n",prefix);
  1908. X        print_lines(cmd_buf,STANDOUT);
  1909. X        break;
  1910. X        }
  1911. X    }
  1912. X    }
  1913. X}
  1914. X
  1915. X#endif
  1916. X
  1917. X/* routine to pass to tputs */
  1918. X
  1919. Xchar
  1920. Xputchr(ch)
  1921. Xregister char ch;
  1922. X{
  1923. X    putchar(ch);
  1924. X#ifdef lint
  1925. X    ch = Null(char);
  1926. X    ch = ch;
  1927. X#endif
  1928. X    return((char) 0);
  1929. X}
  1930. X
  1931. X/* input the 2nd and succeeding characters of a multi-character command */
  1932. X/* returns TRUE if command finished, FALSE if they rubbed out first character */
  1933. X
  1934. Xbool
  1935. Xfinish_command(donewline)
  1936. Xint donewline;
  1937. X{
  1938. X    register char *s;
  1939. X    register bool quoteone = FALSE;
  1940. X
  1941. X    s = buf;
  1942. X    if (s[1] != FINISHCMD)        /* someone faking up a command? */
  1943. X    return TRUE;
  1944. X    do {
  1945. X      top:
  1946. X    if (*(unsigned char *)s < ' ') {
  1947. X        putchar('^');
  1948. X        putchar(*s | 64);
  1949. X    }
  1950. X    else if (*s == '\177') {
  1951. X        putchar('^');
  1952. X        putchar('?');
  1953. X    }
  1954. X    else
  1955. X        putchar(*s);        /* echo previous character */
  1956. X    s++;
  1957. Xre_read:
  1958. X    fflush(stdout);
  1959. X    getcmd(s);
  1960. X    if (quoteone) {
  1961. X        quoteone = FALSE;
  1962. X        continue;
  1963. X    }
  1964. X    if (errno || *s == Ctl('l')) {
  1965. X        *s = Ctl('r');        /* force rewrite on CONT */
  1966. X    }
  1967. X    if (*s == '\033') {        /* substitution desired? */
  1968. X#ifdef ESCSUBS
  1969. X        char tmpbuf[4], *cpybuf;
  1970. X
  1971. X        tmpbuf[0] = '%';
  1972. X        read_tty(&tmpbuf[1],1);
  1973. X#ifdef RAWONLY
  1974. X        tmpbuf[1] &= 0177;
  1975. X#endif
  1976. X        tmpbuf[2] = '\0';
  1977. X        if (tmpbuf[1] == 'h') {
  1978. X        (void) help_subs();
  1979. X        *s = '\0';
  1980. X        reprint();
  1981. X        goto re_read;
  1982. X        }
  1983. X        else if (tmpbuf[1] == '\033') {
  1984. X        *s = '\0';
  1985. X        cpybuf = savestr(buf);
  1986. X        interp(buf, (sizeof buf), cpybuf);
  1987. X        free(cpybuf);
  1988. X        s = buf + strlen(buf);
  1989. X        reprint();
  1990. X        goto re_read;
  1991. X        }
  1992. X        else {
  1993. X        interp(s,(sizeof buf) - (s-buf),tmpbuf);
  1994. X        fputs(s,stdout);
  1995. X        s += strlen(s);
  1996. X        }
  1997. X        goto re_read;
  1998. X#else
  1999. X        notincl("^[");
  2000. X        *s = '\0';
  2001. X        reprint();
  2002. X        goto re_read;
  2003. X#endif
  2004. X    }
  2005. X    else if (*s == ERASECH) {    /* they want to rubout a char? */
  2006. X        rubout();
  2007. X        s--;            /* discount the char rubbed out */
  2008. X        if (*(unsigned char *)s < ' ' || *s == '\177')
  2009. X        rubout();
  2010. X        if (s == buf) {        /* entire string gone? */
  2011. X        fflush(stdout);        /* return to single char command mode */
  2012. X        return FALSE;
  2013. X        }
  2014. X        else
  2015. X        goto re_read;
  2016. X    }
  2017. X    else if (*s == KILLCH) {    /* wipe out the whole line? */
  2018. X        while (s-- != buf) {    /* emulate that many ERASEs */
  2019. X        rubout();
  2020. X        if (*(unsigned char *)s < ' ' || *s == '\177')
  2021. X            rubout();
  2022. X        }
  2023. X        fflush(stdout);
  2024. X        return FALSE;        /* return to single char mode */
  2025. X    }
  2026. X#ifdef WORDERASE
  2027. X    else if (*s == Ctl('w')) {    /* wipe out one word? */
  2028. X        *s-- = ' ';
  2029. X        while (!isspace(*s) || isspace(s[1])) {
  2030. X        rubout();
  2031. X        if (s-- == buf) {
  2032. X            fflush(stdout);
  2033. X            return FALSE;    /* return to single char mode */
  2034. X        }
  2035. X        if (*(unsigned char *)s < ' ' || *s == '\177')
  2036. X            rubout();
  2037. X        }
  2038. X        s++;
  2039. X        goto re_read;
  2040. X    }
  2041. X#endif
  2042. X    else if (*s == Ctl('r')) {
  2043. X        *s = '\0';
  2044. X        reprint();
  2045. X        goto re_read;
  2046. X    }
  2047. X    else if (*s == Ctl('v')) {
  2048. X        putchar('^');
  2049. X        backspace();
  2050. X        fflush(stdout);
  2051. X        getcmd(s);
  2052. X        goto top;
  2053. X    }
  2054. X    else if (*s == '\\') {
  2055. X        quoteone = TRUE;
  2056. X    }
  2057. X    } while (*s != '\n');        /* till a newline (not echoed) */
  2058. X    *s = '\0';                /* terminate the string nicely */
  2059. X    if (donewline)
  2060. X    putchar('\n') FLUSH;
  2061. X    return TRUE;            /* say we succeeded */
  2062. X}
  2063. X
  2064. X/* discard any characters typed ahead */
  2065. X
  2066. Xvoid
  2067. Xeat_typeahead()
  2068. X{
  2069. X#ifdef PUSHBACK
  2070. X    if (!typeahead && nextin==nextout)    /* cancel only keyboard stuff */
  2071. X#else
  2072. X    if (!typeahead)
  2073. X#endif
  2074. X    {
  2075. X#ifdef PENDING
  2076. X    while (input_pending())
  2077. X        read_tty(buf,sizeof(buf));
  2078. X#else /* this is probably v7 */
  2079. X    ioctl(_tty_ch,TIOCSETP,&_tty);
  2080. X#endif
  2081. X    }
  2082. X}
  2083. X
  2084. Xvoid
  2085. Xsettle_down()
  2086. X{
  2087. X    dingaling();
  2088. X    fflush(stdout);
  2089. X    sleep(1);
  2090. X#ifdef PUSHBACK
  2091. X    nextout = nextin;            /* empty circlebuf */
  2092. X#endif
  2093. X    eat_typeahead();
  2094. X}
  2095. X
  2096. X#ifdef PUSHBACK
  2097. X/* read a character from the terminal, with multi-character pushback */
  2098. X
  2099. Xint
  2100. Xread_tty(addr,size)
  2101. Xchar *addr;
  2102. Xint size;
  2103. X{
  2104. X    if (nextout != nextin) {
  2105. X    *addr = circlebuf[nextout++];
  2106. X    nextout %= PUSHSIZE;
  2107. X    return 1;
  2108. X    }
  2109. X    else {
  2110. X    size = read(0,addr,size);
  2111. X#ifdef RAWONLY
  2112. X    *addr &= 0177;
  2113. X#endif
  2114. X    return size;
  2115. X    }
  2116. X}
  2117. X
  2118. X#ifdef PENDING
  2119. X#if ! defined (FIONREAD) && ! defined (RDCHK)
  2120. Xint
  2121. Xcircfill()
  2122. X{
  2123. X    register int Howmany;
  2124. X
  2125. X    errno = 0;
  2126. X    Howmany = read(devtty,circlebuf+nextin,1);
  2127. X
  2128. X    if (Howmany < 0 && (errno == EAGAIN || errno == EINTR))
  2129. X    Howmany = 0;
  2130. X    if (Howmany) {
  2131. X    nextin += Howmany;
  2132. X    nextin %= PUSHSIZE;
  2133. X    }
  2134. X    return Howmany;
  2135. X}
  2136. X#endif /* PENDING */
  2137. X#endif /* FIONREAD */
  2138. X
  2139. Xvoid
  2140. Xpushchar(c)
  2141. Xchar c;
  2142. X{
  2143. X    nextout--;
  2144. X    if (nextout < 0)
  2145. X    nextout = PUSHSIZE - 1;
  2146. X    if (nextout == nextin) {
  2147. X    fputs("\npushback buffer overflow\n",stdout) FLUSH;
  2148. X    sig_catcher(0);
  2149. X    }
  2150. X    circlebuf[nextout] = c;
  2151. X}
  2152. X
  2153. X#else /* PUSHBACK */
  2154. X#ifndef read_tty
  2155. X/* read a character from the terminal, with hacks for O_NDELAY reads */
  2156. X
  2157. Xint
  2158. Xread_tty(addr,size)
  2159. Xchar *addr;
  2160. Xint size;
  2161. X{
  2162. X    if (is_input) {
  2163. X    *addr = pending_ch;
  2164. X    is_input = FALSE;
  2165. X    return 1;
  2166. X    }
  2167. X    else {
  2168. X    size = read(0,addr,size);
  2169. X#ifdef RAWONLY
  2170. X    *addr &= 0177;
  2171. X#endif
  2172. X    return size;
  2173. X    }
  2174. X}
  2175. X#endif /* read_tty */
  2176. X#endif /* PUSHBACK */
  2177. X
  2178. X/* print an underlined string, one way or another */
  2179. X
  2180. Xvoid
  2181. Xunderprint(s)
  2182. Xregister char *s;
  2183. X{
  2184. X    assert(UC);
  2185. X    if (*UC) {        /* char by char underline? */
  2186. X    while (*s) {
  2187. X        if (*(unsigned char *)s < ' ') {
  2188. X        putchar('^');
  2189. X        backspace();/* back up over it */
  2190. X        underchar();/* and do the underline */
  2191. X        putchar(*s+64);
  2192. X        backspace();/* back up over it */
  2193. X        underchar();/* and do the underline */
  2194. X        }
  2195. X        else {
  2196. X        putchar(*s);
  2197. X        backspace();/* back up over it */
  2198. X        underchar();/* and do the underline */
  2199. X        }
  2200. X        s++;
  2201. X    }
  2202. X    }
  2203. X    else {        /* start and stop underline */
  2204. X    underline();    /* start underlining */
  2205. X    while (*s) {
  2206. X        if (*(unsigned char *)s < ' ') {
  2207. X        putchar('^');
  2208. X        putchar(*s+64);
  2209. X        }
  2210. X        else
  2211. X        putchar(*s);
  2212. X        s++;
  2213. X    }
  2214. X    un_underline();    /* stop underlining */
  2215. X    }
  2216. X}
  2217. X
  2218. X/* keep screen from flashing strangely on magic cookie terminals */
  2219. X
  2220. X#ifdef NOFIREWORKS
  2221. Xvoid
  2222. Xno_sofire()
  2223. X{
  2224. X    if (*UP && *SE) {        /* should we disable fireworks? */
  2225. X    putchar('\n');
  2226. X    un_standout();
  2227. X    up_line();
  2228. X    carriage_return();
  2229. X    }
  2230. X}
  2231. X
  2232. Xvoid
  2233. Xno_ulfire()
  2234. X{
  2235. X    if (*UP && *US) {        /* should we disable fireworks? */
  2236. X    putchar('\n');
  2237. X    un_underline();
  2238. X    up_line();
  2239. X    carriage_return();
  2240. X    }
  2241. X}
  2242. X#endif
  2243. X
  2244. X/* get a character into a buffer */
  2245. X
  2246. Xvoid
  2247. Xgetcmd(whatbuf)
  2248. Xregister char *whatbuf;
  2249. X{
  2250. X#ifdef PUSHBACK
  2251. X    register KEYMAP *curmap;
  2252. X    register int i;
  2253. X    bool no_macros; 
  2254. X    int times = 0;            /* loop detector */
  2255. X    char scrchar;
  2256. X
  2257. Xtryagain:
  2258. X    curmap = topmap;
  2259. X    no_macros = (whatbuf != buf && nextin == nextout); 
  2260. X#endif
  2261. X    for (;;) {
  2262. X    int_count = 0;
  2263. X    errno = 0;
  2264. X    if (read_tty(whatbuf,1) < 0){
  2265. X        if (!errno)
  2266. X            errno = EINTR;
  2267. X        if (errno == EINTR)
  2268. X        return;
  2269. X        perror(readerr);
  2270. X        sig_catcher(0);
  2271. X    }
  2272. X#ifdef PUSHBACK
  2273. X    if (*whatbuf & 0200 || no_macros) {
  2274. X        *whatbuf &= 0177;
  2275. X        goto got_canonical;
  2276. X    }
  2277. X    if (curmap == Null(KEYMAP*))
  2278. X        goto got_canonical;
  2279. X    for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){
  2280. X        read_tty(&scrchar,1);
  2281. X    }
  2282. X    switch (curmap->km_type[*whatbuf] & KM_TMASK) {
  2283. X    case KM_NOTHIN:            /* no entry? */
  2284. X        if (curmap == topmap)    /* unmapped canonical */
  2285. X        goto got_canonical;
  2286. X        settle_down();
  2287. X        goto tryagain;
  2288. X    case KM_KEYMAP:            /* another keymap? */
  2289. X        curmap = curmap->km_ptr[*whatbuf].km_km;
  2290. X        assert(curmap != Null(KEYMAP*));
  2291. X        break;
  2292. X    case KM_STRING:            /* a string? */
  2293. X        pushstring(curmap->km_ptr[*whatbuf].km_str);
  2294. X        if (++times > 20) {        /* loop? */
  2295. X        fputs("\nmacro loop?\n",stdout);
  2296. X        settle_down();
  2297. X        }
  2298. X        no_macros = FALSE;
  2299. X        goto tryagain;
  2300. X    }
  2301. X#else
  2302. X#ifdef RAWONLY
  2303. X    *whatbuf &= 0177;
  2304. X#endif
  2305. X    break;
  2306. X#endif
  2307. X    }
  2308. X
  2309. Xgot_canonical:
  2310. X#ifndef TERMIO
  2311. X    if (*whatbuf == '\r')
  2312. X    *whatbuf = '\n';
  2313. X#endif
  2314. X    if (whatbuf == buf)
  2315. X    whatbuf[1] = FINISHCMD;        /* tell finish_command to work */
  2316. X}
  2317. X
  2318. X#ifdef PUSHBACK
  2319. Xvoid
  2320. Xpushstring(str)
  2321. Xchar *str;
  2322. X{
  2323. X    register int i;
  2324. X    char tmpbuf[PUSHSIZE];
  2325. X    register char *s = tmpbuf;
  2326. X
  2327. X    assert(str != Nullch);
  2328. X    interp(s,PUSHSIZE,str);
  2329. X    for (i = strlen(s)-1; i >= 0; --i) {
  2330. X    s[i] ^= 0200; 
  2331. X    pushchar(s[i]);
  2332. X    }
  2333. X}
  2334. X#endif
  2335. X
  2336. Xint
  2337. Xget_anything()
  2338. X{
  2339. X    char tmpbuf[2];
  2340. X
  2341. Xreask_anything:
  2342. X    unflush_output();            /* disable any ^O in effect */
  2343. X    standout();
  2344. X#ifdef VERBOSE
  2345. X    IF(verbose)
  2346. X    fputs("[Type space to continue] ",stdout);
  2347. X    ELSE
  2348. X#endif
  2349. X#ifdef TERSE
  2350. X    fputs("[MORE] ",stdout);
  2351. X#endif
  2352. X    un_standout();
  2353. X    fflush(stdout);
  2354. X    eat_typeahead();
  2355. X    if (int_count) {
  2356. X    return -1;
  2357. X    }
  2358. X    collect_subjects();            /* loads subject cache until */
  2359. X                    /* input is pending */
  2360. X    getcmd(tmpbuf);
  2361. X    if (errno || *tmpbuf == '\f') {
  2362. X    putchar('\n') FLUSH;        /* if return from stop signal */
  2363. X    goto reask_anything;        /* give them a prompt again */
  2364. X    }
  2365. X    if (*tmpbuf == 'h') {
  2366. X#ifdef VERBOSE
  2367. X    IF(verbose)
  2368. X        fputs("\nType q to quit or space to continue.\n",stdout) FLUSH;
  2369. X    ELSE
  2370. X#endif
  2371. X#ifdef TERSE
  2372. X        fputs("\nq to quit, space to continue.\n",stdout) FLUSH;
  2373. X#endif
  2374. X    goto reask_anything;
  2375. X    }
  2376. X    else if (*tmpbuf != ' ' && *tmpbuf != '\n') {
  2377. X    carriage_return();
  2378. X    erase_eol();    /* erase the prompt */
  2379. X    carriage_return();
  2380. X    return *tmpbuf == 'q' ? -1 : *tmpbuf;
  2381. X    }
  2382. X    if (*tmpbuf == '\n') {
  2383. X    page_line = LINES - 1;
  2384. X    carriage_return();
  2385. X    erase_eol();
  2386. X    carriage_return();
  2387. X    }
  2388. X    else {
  2389. X    page_line = 1;
  2390. X    if (erase_screen)        /* -e? */
  2391. X        clear();            /* clear screen */
  2392. X    else {
  2393. X        carriage_return();
  2394. X        erase_eol();        /* erase the prompt */
  2395. X        carriage_return();
  2396. X    }
  2397. X    }
  2398. X    return 0;
  2399. X}
  2400. X
  2401. X#ifdef USETHREADS
  2402. Xint
  2403. Xpause_getcmd()
  2404. X{
  2405. X    unflush_output();            /* disable any ^O in effect */
  2406. X    standout();
  2407. X#ifdef VERBOSE
  2408. X    IF(verbose)
  2409. X    fputs("[Type space or a command] ",stdout);
  2410. X    ELSE
  2411. X#endif
  2412. X#ifdef TERSE
  2413. X    fputs("[CMD] ",stdout);
  2414. X#endif
  2415. X    un_standout();
  2416. X    fflush(stdout);
  2417. X    eat_typeahead();
  2418. X    if (int_count) {
  2419. X    return -1;
  2420. X    }
  2421. X    getcmd(buf);
  2422. X    if (errno || *buf == '\f') {
  2423. X    return 0;            /* if return from stop signal */
  2424. X    }
  2425. X    else if (*buf != ' ') {
  2426. X    carriage_return();
  2427. X    erase_eol();    /* erase the prompt */
  2428. X    carriage_return();
  2429. X    return *buf;
  2430. X    }
  2431. X    return 0;
  2432. X}
  2433. X#endif
  2434. X
  2435. Xvoid
  2436. Xin_char(prompt, newmode)
  2437. Xchar *prompt;
  2438. Xchar newmode;
  2439. X{
  2440. X    char oldmode = mode;
  2441. X
  2442. Xreask_in_char:
  2443. X    unflush_output();            /* disable any ^O in effect */
  2444. X    fputs(prompt,stdout);
  2445. X    fflush(stdout);
  2446. X    eat_typeahead();
  2447. X    mode = newmode;
  2448. X    getcmd(buf);
  2449. X    if (errno || *buf == '\f') {
  2450. X    putchar('\n') FLUSH;        /* if return from stop signal */
  2451. X    goto reask_in_char;        /* give them a prompt again */
  2452. X    }
  2453. X    mode = oldmode;
  2454. X}
  2455. X
  2456. Xint
  2457. Xprint_lines(what_to_print,hilite)
  2458. Xchar *what_to_print;
  2459. Xint hilite;
  2460. X{
  2461. X    register char *s;
  2462. X    register int i;
  2463. X
  2464. X    if (page_line < 0)            /* they do not want to see this? */
  2465. X    return -1;
  2466. X    for (s=what_to_print; *s; ) {
  2467. X    if (page_line >= LINES || int_count) {
  2468. X        if (i = -1, int_count || (i = get_anything())) {
  2469. X        page_line = -1;        /* disable further print_lines */
  2470. X        return i;
  2471. X        }
  2472. X    }
  2473. X    page_line++;
  2474. X    if (hilite == STANDOUT) {
  2475. X#ifdef NOFIREWORKS
  2476. X        if (erase_screen)
  2477. X        no_sofire();
  2478. X#endif
  2479. X        standout();
  2480. X    }
  2481. X    else if (hilite == UNDERLINE) {
  2482. X#ifdef NOFIREWORKS
  2483. X        if (erase_screen)
  2484. X        no_ulfire();
  2485. X#endif
  2486. X        underline();
  2487. X    }
  2488. X    for (i=0; i<COLS; i++) {
  2489. X        if (!*s)
  2490. X        break;
  2491. X        if (*(unsigned char *)s >= ' ')
  2492. X        putchar(*s);
  2493. X        else if (*s == '\t') {
  2494. X        putchar(*s);
  2495. X        i = ((i+8) & ~7) - 1; 
  2496. X        }
  2497. X        else if (*s == '\n') {
  2498. X        i = 32000;
  2499. X        }
  2500. X        else {
  2501. X        i++;
  2502. X        putchar('^');
  2503. X        putchar(*s + 64);
  2504. X        }
  2505. X        s++;
  2506. X    }
  2507. X    if (i) {
  2508. X        if (hilite == STANDOUT)
  2509. X        un_standout();
  2510. X        else if (hilite == UNDERLINE)
  2511. X        un_underline();
  2512. X        if (AM && i == COLS)
  2513. X        fflush(stdout);
  2514. X        else
  2515. X        putchar('\n') FLUSH;
  2516. X    }
  2517. X    }
  2518. X    return 0;
  2519. X}
  2520. X
  2521. Xvoid
  2522. Xpage_init()
  2523. X{
  2524. X    page_line = 1;
  2525. X    if (erase_screen)
  2526. X    clear();
  2527. X    else
  2528. X    putchar('\n') FLUSH;
  2529. X}
  2530. X
  2531. Xvoid
  2532. Xpad(num)
  2533. Xint num;
  2534. X{
  2535. X    register int i;
  2536. X
  2537. X    for (i = num; i; --i)
  2538. X    putchar(PC);
  2539. X    fflush(stdout);
  2540. X}
  2541. X
  2542. X/* echo the command just typed */
  2543. X
  2544. X#ifdef VERIFY
  2545. Xvoid
  2546. Xprintcmd()
  2547. X{
  2548. X    if (verify && buf[1] == FINISHCMD) {
  2549. X    if (*(unsigned char *)buf < ' ') {
  2550. X        putchar('^');
  2551. X        putchar(*buf | 64);
  2552. X        backspace();
  2553. X        backspace();
  2554. X    }
  2555. X    else {
  2556. X        putchar(*buf);
  2557. X        backspace();
  2558. X    }
  2559. X    fflush(stdout);
  2560. X    }
  2561. X}
  2562. X#endif
  2563. X
  2564. Xvoid
  2565. Xrubout()
  2566. X{
  2567. X    backspace();            /* do the old backspace, */
  2568. X    putchar(' ');            /*   space, */
  2569. X    backspace();            /*     backspace trick */
  2570. X}
  2571. X
  2572. Xvoid
  2573. Xreprint()
  2574. X{
  2575. X    register char *s;
  2576. X
  2577. X    fputs("^R\n",stdout) FLUSH;
  2578. X    for (s = buf; *s; s++) {
  2579. X    if (*(unsigned char *)s < ' ') {
  2580. X        putchar('^');
  2581. X        putchar(*s | 64);
  2582. X    }
  2583. X    else
  2584. X        putchar(*s);
  2585. X    }
  2586. X}
  2587. X
  2588. X#if defined(CLEAREOL) || defined(USETHREADS)
  2589. Xvoid
  2590. Xhome_cursor()
  2591. X{
  2592. X    char *tgoto();
  2593. X
  2594. X    if (!*HO) {            /* no home sequence? */
  2595. X    if (!*CM) {        /* no cursor motion either? */
  2596. X        fputs ("\n\n\n", stdout);
  2597. X        return;        /* forget it. */
  2598. X    }
  2599. X    tputs (tgoto (CM, 0, 0), 1, putchr);    /* go to home via CM */
  2600. X    return;
  2601. X    }
  2602. X    else {            /* we have home sequence */
  2603. X    tputs (HO, 1, putchr);    /* home via HO */
  2604. X    }
  2605. X}
  2606. X#endif
  2607. X
  2608. X#ifdef USETHREADS
  2609. Xvoid
  2610. Xgoto_line(from,to)    /* assumes caller is already at beginning of line */
  2611. Xint from,to;
  2612. X{
  2613. X    char *tgoto(), *str;
  2614. X    int cmcost;
  2615. X
  2616. X    if (from == to) {
  2617. X    return;
  2618. X    }
  2619. X    if (*CM && !muck_up_clear) {
  2620. X    cmcost = strlen(str = tgoto(CM,0,to));
  2621. X    } else {
  2622. X    cmcost = 9999;
  2623. X    }
  2624. X    if (to > from) {
  2625. X      go_down:
  2626. X    if (to - from <= cmcost) {
  2627. X        while(from++ < to) {
  2628. X        putchar('\n');
  2629. X        }
  2630. X        return;
  2631. X    }
  2632. X    } else if(*UP) {
  2633. X    if ((from - to) * upcost <= cmcost) {
  2634. X        while(from-- > to) {
  2635. X        tputs(UP,1,putchr);
  2636. X        }
  2637. X        return;
  2638. X    }
  2639. X    } else if (cmcost == 9999) {
  2640. X    home_cursor();
  2641. X    from = 0;
  2642. X    goto go_down;
  2643. X    }
  2644. X    tputs(str,1,putchr);
  2645. X}
  2646. X#endif
  2647. X
  2648. X
  2649. Xvoid
  2650. Xline_col_calcs()
  2651. X{
  2652. X     if (LINES > 0) {            /* is this a crt? */
  2653. X      if ((!initlines) || (!initlines_specified))
  2654. X           /* no -i or unreasonable value for initlines */
  2655. X           if (ospeed >= B9600)     /* whole page at >= 9600 baud */
  2656. X            initlines = LINES;
  2657. X           else if (ospeed >= B4800)/* 16 lines at 4800 */
  2658. X            initlines = 16;
  2659. X           else            /* otherwise just header */
  2660. X            initlines = 8;
  2661. X     }
  2662. X     else {                /* not a crt */
  2663. X      LINES = 30000;        /* so don't page */
  2664. X      CL = "\n\n";            /* put a couple of lines between */
  2665. X      if ((!initlines) || (!initlines_specified))
  2666. X           /* make initlines reasonable */
  2667. X           initlines = 8;
  2668. X     }
  2669. X     if (COLS <= 0)
  2670. X      COLS = 80;
  2671. X}
  2672. X
  2673. X
  2674. X#ifdef SIGWINCH
  2675. Xint
  2676. Xwinch_catcher()
  2677. X{
  2678. X     /* Come here if window size change signal received */
  2679. X#ifdef TIOCGWINSZ
  2680. X     struct winsize ws;
  2681. X
  2682. X     if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) {
  2683. X          LINES = ws.ws_row;
  2684. X          COLS = ws.ws_col;
  2685. X          line_col_calcs();
  2686. X     }
  2687. X#else
  2688. X     ???????
  2689. X     /* Well, if SIGWINCH is defined, but TIOCGWINSZ isn't, there's    */
  2690. X     /* almost certainly something wrong.  Figure it out for yourself, */
  2691. X     /* because I don't know now to deal :-)                           */
  2692. X#endif
  2693. X}
  2694. X#endif
  2695. END_OF_FILE
  2696.   if test 25986 -ne `wc -c <'term.c'`; then
  2697.     echo shar: \"'term.c'\" unpacked with wrong size!
  2698.   fi
  2699.   # end of 'term.c'
  2700. fi
  2701. echo shar: End of archive 7 \(of 14\).
  2702. cp /dev/null ark7isdone
  2703. MISSING=""
  2704. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  2705.     if test ! -f ark${I}isdone ; then
  2706.     MISSING="${MISSING} ${I}"
  2707.     fi
  2708. done
  2709. if test "${MISSING}" = "" ; then
  2710.     echo You have unpacked all 14 archives.
  2711.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2712. else
  2713.     echo You still must unpack the following archives:
  2714.     echo "        " ${MISSING}
  2715. fi
  2716. exit 0
  2717.